7 5 日 前
コミット
01fb87187e
100 ファイル変更18037 行追加5 行削除
  1. BIN
      OIP-C (1).jpg
  2. 3 3
      myapp/src/app/tab1/tab1.page.html
  3. 3 0
      myapp/src/app/tab5/user-dashboard.page.html
  4. 11 0
      myapp/src/app/tab5/user-dashboard.page.scss
  5. 61 2
      myapp/src/app/tab5/user-dashboard.page.ts
  6. BIN
      myapp/src/assets/images/1.jpg
  7. 37 0
      myapp/src/global.scss
  8. 16 0
      node_modules/.bin/mkdirp
  9. 17 0
      node_modules/.bin/mkdirp.cmd
  10. 28 0
      node_modules/.bin/mkdirp.ps1
  11. 219 0
      node_modules/.package-lock.json
  12. 1 0
      node_modules/append-field/.npmignore
  13. 21 0
      node_modules/append-field/LICENSE
  14. 44 0
      node_modules/append-field/README.md
  15. 12 0
      node_modules/append-field/index.js
  16. 53 0
      node_modules/append-field/lib/parse-path.js
  17. 64 0
      node_modules/append-field/lib/set-value.js
  18. 19 0
      node_modules/append-field/package.json
  19. 19 0
      node_modules/append-field/test/forms.js
  20. 21 0
      node_modules/buffer-from/LICENSE
  21. 72 0
      node_modules/buffer-from/index.js
  22. 19 0
      node_modules/buffer-from/package.json
  23. 69 0
      node_modules/buffer-from/readme.md
  24. 5 0
      node_modules/busboy/.eslintrc.js
  25. 24 0
      node_modules/busboy/.github/workflows/ci.yml
  26. 23 0
      node_modules/busboy/.github/workflows/lint.yml
  27. 19 0
      node_modules/busboy/LICENSE
  28. 191 0
      node_modules/busboy/README.md
  29. 149 0
      node_modules/busboy/bench/bench-multipart-fields-100mb-big.js
  30. 143 0
      node_modules/busboy/bench/bench-multipart-fields-100mb-small.js
  31. 154 0
      node_modules/busboy/bench/bench-multipart-files-100mb-big.js
  32. 148 0
      node_modules/busboy/bench/bench-multipart-files-100mb-small.js
  33. 101 0
      node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js
  34. 84 0
      node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js
  35. 57 0
      node_modules/busboy/lib/index.js
  36. 653 0
      node_modules/busboy/lib/types/multipart.js
  37. 350 0
      node_modules/busboy/lib/types/urlencoded.js
  38. 596 0
      node_modules/busboy/lib/utils.js
  39. 22 0
      node_modules/busboy/package.json
  40. 109 0
      node_modules/busboy/test/common.js
  41. 94 0
      node_modules/busboy/test/test-types-multipart-charsets.js
  42. 102 0
      node_modules/busboy/test/test-types-multipart-stream-pause.js
  43. 1053 0
      node_modules/busboy/test/test-types-multipart.js
  44. 488 0
      node_modules/busboy/test/test-types-urlencoded.js
  45. 20 0
      node_modules/busboy/test/test.js
  46. 24 0
      node_modules/concat-stream/LICENSE
  47. 144 0
      node_modules/concat-stream/index.js
  48. 55 0
      node_modules/concat-stream/package.json
  49. 102 0
      node_modules/concat-stream/readme.md
  50. 19 0
      node_modules/core-util-is/LICENSE
  51. 3 0
      node_modules/core-util-is/README.md
  52. 107 0
      node_modules/core-util-is/lib/util.js
  53. 38 0
      node_modules/core-util-is/package.json
  54. 16 0
      node_modules/inherits/LICENSE
  55. 42 0
      node_modules/inherits/README.md
  56. 9 0
      node_modules/inherits/inherits.js
  57. 27 0
      node_modules/inherits/inherits_browser.js
  58. 29 0
      node_modules/inherits/package.json
  59. 1 0
      node_modules/isarray/.npmignore
  60. 4 0
      node_modules/isarray/.travis.yml
  61. 6 0
      node_modules/isarray/Makefile
  62. 60 0
      node_modules/isarray/README.md
  63. 19 0
      node_modules/isarray/component.json
  64. 5 0
      node_modules/isarray/index.js
  65. 45 0
      node_modules/isarray/package.json
  66. 20 0
      node_modules/isarray/test.js
  67. 22 0
      node_modules/media-typer/HISTORY.md
  68. 22 0
      node_modules/media-typer/LICENSE
  69. 81 0
      node_modules/media-typer/README.md
  70. 270 0
      node_modules/media-typer/index.js
  71. 26 0
      node_modules/media-typer/package.json
  72. 507 0
      node_modules/mime-db/HISTORY.md
  73. 23 0
      node_modules/mime-db/LICENSE
  74. 100 0
      node_modules/mime-db/README.md
  75. 8519 0
      node_modules/mime-db/db.json
  76. 12 0
      node_modules/mime-db/index.js
  77. 60 0
      node_modules/mime-db/package.json
  78. 397 0
      node_modules/mime-types/HISTORY.md
  79. 23 0
      node_modules/mime-types/LICENSE
  80. 113 0
      node_modules/mime-types/README.md
  81. 188 0
      node_modules/mime-types/index.js
  82. 44 0
      node_modules/mime-types/package.json
  83. 29 0
      node_modules/minimist/.eslintrc
  84. 12 0
      node_modules/minimist/.github/FUNDING.yml
  85. 14 0
      node_modules/minimist/.nycrc
  86. 298 0
      node_modules/minimist/CHANGELOG.md
  87. 18 0
      node_modules/minimist/LICENSE
  88. 121 0
      node_modules/minimist/README.md
  89. 4 0
      node_modules/minimist/example/parse.js
  90. 263 0
      node_modules/minimist/index.js
  91. 75 0
      node_modules/minimist/package.json
  92. 34 0
      node_modules/minimist/test/all_bool.js
  93. 177 0
      node_modules/minimist/test/bool.js
  94. 43 0
      node_modules/minimist/test/dash.js
  95. 37 0
      node_modules/minimist/test/default_bool.js
  96. 24 0
      node_modules/minimist/test/dotted.js
  97. 32 0
      node_modules/minimist/test/kv_short.js
  98. 33 0
      node_modules/minimist/test/long.js
  99. 38 0
      node_modules/minimist/test/num.js
  100. 209 0
      node_modules/minimist/test/parse.js

BIN
OIP-C (1).jpg


+ 3 - 3
myapp/src/app/tab1/tab1.page.html

@@ -34,15 +34,15 @@
 
   <!-- 社区动态信息流 -->
   <div class="community-feed">
-    <ion-list lines="none">
+    <ion-list lines="none" style="max-height: 50vh; overflow-y: auto;">
       <ion-list-header>
         <ion-label>社区互助动态</ion-label>
         <ion-chip (click)="importMessage()">导入测试数据</ion-chip>
       </ion-list-header>
       
       <ion-item *ngFor="let item of Message" 
-                [class.high-points]="item.points > 40"
-                (click)="goDynamic('123'); playPointsAnimation($event)">
+                [class.high-points]="item.points > 40">
+                
         <ion-avatar slot="start">
           <img [src]="'https://ionicframework.com/docs/img/demos/avatar.svg'" />
         </ion-avatar>

+ 3 - 0
myapp/src/app/tab5/user-dashboard.page.html

@@ -11,6 +11,9 @@
   <ion-card>
     <ion-card-header>
       <ion-card-title>欢迎, {{currentUser?.data?.username}}</ion-card-title>
+      <ion-avatar class="user-avatar">
+        <img [src]="currentUser?.data?.avatar || 'assets/images/1.jpg'" alt="用户头像"/>
+      </ion-avatar>
     </ion-card-header>
     <ion-card-content>
       <p>用户ID: {{currentUser?.id}}</p>

+ 11 - 0
myapp/src/app/tab5/user-dashboard.page.scss

@@ -0,0 +1,11 @@
+.user-avatar {
+  width: 80px;
+  height: 80px;
+  margin: 10px auto;
+  cursor: pointer;
+  
+  img {
+    border: 2px solid var(--ion-color-primary);
+    border-radius: 50%;
+  }
+}

+ 61 - 2
myapp/src/app/tab5/user-dashboard.page.ts

@@ -14,9 +14,12 @@ import { EditProfileComponent } from './edit-profile.component'; // 假设编辑
   standalone: true 
 })
 export class UserDashboardPage {
- 
   user = new CloudUser();
-  currentUser: any = null;
+  currentUser: any = {
+    data: {
+      avatar: 'assets/images/1.jpg' // 使用相对路径
+    }
+  };
      
   // 修改为CloudObject数组类型
   qualification: CloudObject[] = [];
@@ -27,6 +30,10 @@ export class UserDashboardPage {
 
   async getCurrentUser() {
     this.currentUser = await this.user.current();
+    // 确保用户有默认头像
+    if(!this.currentUser.data.avatar) {
+      this.currentUser.data.avatar = 'assets/images/1.jpg';
+    }
     const query = new CloudQuery('Qualification');
     this.qualification = await query.find();
   }
@@ -67,4 +74,56 @@ export class UserDashboardPage {
   goToUploadQualification() {
     this.router.navigate(['/tabs/tab5/upload-qualification']);
   }
+
+  async uploadAvatar() {
+    if (!this.user.sessionToken) {
+      alert('请先登录');
+      return;
+    }
+  
+    const input = document.createElement('input');
+    input.type = 'file';
+    input.accept = 'image/*';
+    
+    input.onchange = async (e: any) => {
+      const file = e.target.files[0];
+      if (file) {
+        try {
+          const formData = new FormData();
+          formData.append('file', file);
+          
+          // 添加文件名参数
+          const response = await fetch(`http://dev.fmode.cn:1337/parse/files/${file.name}`, {
+            method: 'POST',
+            headers: {
+              'X-Parse-Application-Id': 'dev',
+              'X-Parse-Session-Token': this.user.sessionToken as string
+            },
+            body: file  // 直接上传文件对象
+          });
+          
+          if (!response.ok) {
+            throw new Error(`上传失败: ${response.status}`);
+          }
+          
+          const result = await response.json();
+          if (result.url) {
+            // 更新用户头像URL
+            this.currentUser.data.avatar = result.url;
+            this.user.set({ avatar: result.url });
+            await this.user.save();
+            this.currentUser = await this.user.current();
+          }
+        } catch (error) {
+          console.error('上传头像失败:', error);
+          let errorMessage = '上传失败';
+          if (error instanceof Error) {
+            errorMessage += `: ${error.message}`;
+          }
+          alert(errorMessage);
+        }
+      }
+    };
+    input.click();
+  }
 }

BIN
myapp/src/assets/images/1.jpg


+ 37 - 0
myapp/src/global.scss

@@ -47,6 +47,43 @@ html, body {
   margin: 0;
   padding: 0;
   overflow-x: hidden;
+  font-size: 16px; /* 基础字体放大 */
+}
+
+ion-app {
+  height: 100vh; /* 改为全屏高度 */
+  width: 100vw; /* 改为全屏宽度 */
+  max-width: none; /* 移除最大宽度限制 */
+}
+
+/* 全局放大设置 */
+ion-content {
+  --ion-font-family: system-ui;
+  font-size: 1.1rem; /* 内容区域字体放大 */
+  --padding-top: 16px;
+  --padding-bottom: 16px;
+  --padding-start: 16px;
+  --padding-end: 16px;
+}
+
+ion-button {
+  font-size: 1.1rem; /* 按钮文字放大 */
+  height: 48px; /* 按钮高度放大 */
+}
+
+ion-card {
+  margin: 16px;
+  border-radius: 12px;
+  font-size: 1.1rem; /* 卡片内容放大 */
+}
+
+ion-item {
+  --min-height: 56px; /* 表单项高度放大 */
+}
+
+ion-avatar {
+  width: 96px !important; /* 头像尺寸放大 */
+  height: 96px !important;
 }
 
 ion-app {

+ 16 - 0
node_modules/.bin/mkdirp

@@ -0,0 +1,16 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+    *CYGWIN*|*MINGW*|*MSYS*)
+        if command -v cygpath > /dev/null 2>&1; then
+            basedir=`cygpath -w "$basedir"`
+        fi
+    ;;
+esac
+
+if [ -x "$basedir/node" ]; then
+  exec "$basedir/node"  "$basedir/../mkdirp/bin/cmd.js" "$@"
+else 
+  exec node  "$basedir/../mkdirp/bin/cmd.js" "$@"
+fi

+ 17 - 0
node_modules/.bin/mkdirp.cmd

@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+  SET "_prog=%dp0%\node.exe"
+) ELSE (
+  SET "_prog=node"
+  SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%"  "%dp0%\..\mkdirp\bin\cmd.js" %*

+ 28 - 0
node_modules/.bin/mkdirp.ps1

@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+  # Fix case when both the Windows and Linux builds of Node
+  # are installed in the same directory
+  $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "$basedir/node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
+  } else {
+    & "$basedir/node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
+  }
+  $ret=$LASTEXITCODE
+} else {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
+  } else {
+    & "node$exe"  "$basedir/../mkdirp/bin/cmd.js" $args
+  }
+  $ret=$LASTEXITCODE
+}
+exit $ret

+ 219 - 0
node_modules/.package-lock.json

@@ -0,0 +1,219 @@
+{
+  "name": "workspace",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "node_modules/append-field": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/append-field/-/append-field-1.0.0.tgz",
+      "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
+      "license": "MIT"
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "license": "MIT"
+    },
+    "node_modules/busboy": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz",
+      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+      "dependencies": {
+        "streamsearch": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=10.16.0"
+      }
+    },
+    "node_modules/concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "engines": [
+        "node >= 0.8"
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "license": "MIT"
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "license": "ISC"
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+      "license": "MIT"
+    },
+    "node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "license": "MIT",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
+      "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+      "license": "MIT",
+      "dependencies": {
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/multer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/multer/-/multer-2.0.0.tgz",
+      "integrity": "sha512-bS8rPZurbAuHGAnApbM9d4h1wSoYqrOqkE+6a64KLMK9yWU7gJXBDDVklKQ3TPi9DRb85cRs6yXaC0+cjxRtRg==",
+      "license": "MIT",
+      "dependencies": {
+        "append-field": "^1.0.0",
+        "busboy": "^1.0.0",
+        "concat-stream": "^1.5.2",
+        "mkdirp": "^0.5.4",
+        "object-assign": "^4.1.1",
+        "type-is": "^1.6.4",
+        "xtend": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 10.16.0"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "license": "MIT"
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "license": "MIT",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "license": "MIT"
+    },
+    "node_modules/streamsearch": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz",
+      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "license": "MIT",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "license": "MIT",
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+      "license": "MIT"
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "license": "MIT"
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4"
+      }
+    }
+  }
+}

+ 1 - 0
node_modules/append-field/.npmignore

@@ -0,0 +1 @@
+node_modules/

+ 21 - 0
node_modules/append-field/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Linus Unnebäck
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 44 - 0
node_modules/append-field/README.md

@@ -0,0 +1,44 @@
+# `append-field`
+
+A [W3C HTML JSON forms spec](http://www.w3.org/TR/html-json-forms/) compliant
+field appender (for lack of a better name). Useful for people implementing
+`application/x-www-form-urlencoded` and `multipart/form-data` parsers.
+
+It works best on objects created with `Object.create(null)`. Otherwise it might
+conflict with variables from the prototype (e.g. `hasOwnProperty`).
+
+## Installation
+
+```sh
+npm install --save append-field
+```
+
+## Usage
+
+```javascript
+var appendField = require('append-field')
+var obj = Object.create(null)
+
+appendField(obj, 'pets[0][species]', 'Dahut')
+appendField(obj, 'pets[0][name]', 'Hypatia')
+appendField(obj, 'pets[1][species]', 'Felis Stultus')
+appendField(obj, 'pets[1][name]', 'Billie')
+
+console.log(obj)
+```
+
+```text
+{ pets:
+   [ { species: 'Dahut', name: 'Hypatia' },
+     { species: 'Felis Stultus', name: 'Billie' } ] }
+```
+
+## API
+
+### `appendField(store, key, value)`
+
+Adds the field named `key` with the value `value` to the object `store`.
+
+## License
+
+MIT

+ 12 - 0
node_modules/append-field/index.js

@@ -0,0 +1,12 @@
+var parsePath = require('./lib/parse-path')
+var setValue = require('./lib/set-value')
+
+function appendField (store, key, value) {
+  var steps = parsePath(key)
+
+  steps.reduce(function (context, step) {
+    return setValue(context, step, context[step.key], value)
+  }, store)
+}
+
+module.exports = appendField

+ 53 - 0
node_modules/append-field/lib/parse-path.js

@@ -0,0 +1,53 @@
+var reFirstKey = /^[^\[]*/
+var reDigitPath = /^\[(\d+)\]/
+var reNormalPath = /^\[([^\]]+)\]/
+
+function parsePath (key) {
+  function failure () {
+    return [{ type: 'object', key: key, last: true }]
+  }
+
+  var firstKey = reFirstKey.exec(key)[0]
+  if (!firstKey) return failure()
+
+  var len = key.length
+  var pos = firstKey.length
+  var tail = { type: 'object', key: firstKey }
+  var steps = [tail]
+
+  while (pos < len) {
+    var m
+
+    if (key[pos] === '[' && key[pos + 1] === ']') {
+      pos += 2
+      tail.append = true
+      if (pos !== len) return failure()
+      continue
+    }
+
+    m = reDigitPath.exec(key.substring(pos))
+    if (m !== null) {
+      pos += m[0].length
+      tail.nextType = 'array'
+      tail = { type: 'array', key: parseInt(m[1], 10) }
+      steps.push(tail)
+      continue
+    }
+
+    m = reNormalPath.exec(key.substring(pos))
+    if (m !== null) {
+      pos += m[0].length
+      tail.nextType = 'object'
+      tail = { type: 'object', key: m[1] }
+      steps.push(tail)
+      continue
+    }
+
+    return failure()
+  }
+
+  tail.last = true
+  return steps
+}
+
+module.exports = parsePath

+ 64 - 0
node_modules/append-field/lib/set-value.js

@@ -0,0 +1,64 @@
+function valueType (value) {
+  if (value === undefined) return 'undefined'
+  if (Array.isArray(value)) return 'array'
+  if (typeof value === 'object') return 'object'
+  return 'scalar'
+}
+
+function setLastValue (context, step, currentValue, entryValue) {
+  switch (valueType(currentValue)) {
+    case 'undefined':
+      if (step.append) {
+        context[step.key] = [entryValue]
+      } else {
+        context[step.key] = entryValue
+      }
+      break
+    case 'array':
+      context[step.key].push(entryValue)
+      break
+    case 'object':
+      return setLastValue(currentValue, { type: 'object', key: '', last: true }, currentValue[''], entryValue)
+    case 'scalar':
+      context[step.key] = [context[step.key], entryValue]
+      break
+  }
+
+  return context
+}
+
+function setValue (context, step, currentValue, entryValue) {
+  if (step.last) return setLastValue(context, step, currentValue, entryValue)
+
+  var obj
+  switch (valueType(currentValue)) {
+    case 'undefined':
+      if (step.nextType === 'array') {
+        context[step.key] = []
+      } else {
+        context[step.key] = Object.create(null)
+      }
+      return context[step.key]
+    case 'object':
+      return context[step.key]
+    case 'array':
+      if (step.nextType === 'array') {
+        return currentValue
+      }
+
+      obj = Object.create(null)
+      context[step.key] = obj
+      currentValue.forEach(function (item, i) {
+        if (item !== undefined) obj['' + i] = item
+      })
+
+      return obj
+    case 'scalar':
+      obj = Object.create(null)
+      obj[''] = currentValue
+      context[step.key] = obj
+      return obj
+  }
+}
+
+module.exports = setValue

+ 19 - 0
node_modules/append-field/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "append-field",
+  "version": "1.0.0",
+  "license": "MIT",
+  "author": "Linus Unnebäck <linus@folkdatorn.se>",
+  "main": "index.js",
+  "devDependencies": {
+    "mocha": "^2.2.4",
+    "standard": "^6.0.5",
+    "testdata-w3c-json-form": "^0.2.0"
+  },
+  "scripts": {
+    "test": "standard && mocha"
+  },
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/LinusU/node-append-field.git"
+  }
+}

+ 19 - 0
node_modules/append-field/test/forms.js

@@ -0,0 +1,19 @@
+/* eslint-env mocha */
+
+var assert = require('assert')
+var appendField = require('../')
+var testData = require('testdata-w3c-json-form')
+
+describe('Append Field', function () {
+  for (var test of testData) {
+    it('handles ' + test.name, function () {
+      var store = Object.create(null)
+
+      for (var field of test.fields) {
+        appendField(store, field.key, field.value)
+      }
+
+      assert.deepEqual(store, test.expected)
+    })
+  }
+})

+ 21 - 0
node_modules/buffer-from/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2016, 2018 Linus Unnebäck
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 72 - 0
node_modules/buffer-from/index.js

@@ -0,0 +1,72 @@
+/* eslint-disable node/no-deprecated-api */
+
+var toString = Object.prototype.toString
+
+var isModern = (
+  typeof Buffer !== 'undefined' &&
+  typeof Buffer.alloc === 'function' &&
+  typeof Buffer.allocUnsafe === 'function' &&
+  typeof Buffer.from === 'function'
+)
+
+function isArrayBuffer (input) {
+  return toString.call(input).slice(8, -1) === 'ArrayBuffer'
+}
+
+function fromArrayBuffer (obj, byteOffset, length) {
+  byteOffset >>>= 0
+
+  var maxLength = obj.byteLength - byteOffset
+
+  if (maxLength < 0) {
+    throw new RangeError("'offset' is out of bounds")
+  }
+
+  if (length === undefined) {
+    length = maxLength
+  } else {
+    length >>>= 0
+
+    if (length > maxLength) {
+      throw new RangeError("'length' is out of bounds")
+    }
+  }
+
+  return isModern
+    ? Buffer.from(obj.slice(byteOffset, byteOffset + length))
+    : new Buffer(new Uint8Array(obj.slice(byteOffset, byteOffset + length)))
+}
+
+function fromString (string, encoding) {
+  if (typeof encoding !== 'string' || encoding === '') {
+    encoding = 'utf8'
+  }
+
+  if (!Buffer.isEncoding(encoding)) {
+    throw new TypeError('"encoding" must be a valid string encoding')
+  }
+
+  return isModern
+    ? Buffer.from(string, encoding)
+    : new Buffer(string, encoding)
+}
+
+function bufferFrom (value, encodingOrOffset, length) {
+  if (typeof value === 'number') {
+    throw new TypeError('"value" argument must not be a number')
+  }
+
+  if (isArrayBuffer(value)) {
+    return fromArrayBuffer(value, encodingOrOffset, length)
+  }
+
+  if (typeof value === 'string') {
+    return fromString(value, encodingOrOffset)
+  }
+
+  return isModern
+    ? Buffer.from(value)
+    : new Buffer(value)
+}
+
+module.exports = bufferFrom

+ 19 - 0
node_modules/buffer-from/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "buffer-from",
+  "version": "1.1.2",
+  "license": "MIT",
+  "repository": "LinusU/buffer-from",
+  "files": [
+    "index.js"
+  ],
+  "scripts": {
+    "test": "standard && node test"
+  },
+  "devDependencies": {
+    "standard": "^12.0.1"
+  },
+  "keywords": [
+    "buffer",
+    "buffer from"
+  ]
+}

+ 69 - 0
node_modules/buffer-from/readme.md

@@ -0,0 +1,69 @@
+# Buffer From
+
+A [ponyfill](https://ponyfill.com) for `Buffer.from`, uses native implementation if available.
+
+## Installation
+
+```sh
+npm install --save buffer-from
+```
+
+## Usage
+
+```js
+const bufferFrom = require('buffer-from')
+
+console.log(bufferFrom([1, 2, 3, 4]))
+//=> <Buffer 01 02 03 04>
+
+const arr = new Uint8Array([1, 2, 3, 4])
+console.log(bufferFrom(arr.buffer, 1, 2))
+//=> <Buffer 02 03>
+
+console.log(bufferFrom('test', 'utf8'))
+//=> <Buffer 74 65 73 74>
+
+const buf = bufferFrom('test')
+console.log(bufferFrom(buf))
+//=> <Buffer 74 65 73 74>
+```
+
+## API
+
+### bufferFrom(array)
+
+- `array` &lt;Array&gt;
+
+Allocates a new `Buffer` using an `array` of octets.
+
+### bufferFrom(arrayBuffer[, byteOffset[, length]])
+
+- `arrayBuffer` &lt;ArrayBuffer&gt; The `.buffer` property of a TypedArray or ArrayBuffer
+- `byteOffset` &lt;Integer&gt; Where to start copying from `arrayBuffer`. **Default:** `0`
+- `length` &lt;Integer&gt; How many bytes to copy from `arrayBuffer`. **Default:** `arrayBuffer.length - byteOffset`
+
+When passed a reference to the `.buffer` property of a TypedArray instance, the
+newly created `Buffer` will share the same allocated memory as the TypedArray.
+
+The optional `byteOffset` and `length` arguments specify a memory range within
+the `arrayBuffer` that will be shared by the `Buffer`.
+
+### bufferFrom(buffer)
+
+- `buffer` &lt;Buffer&gt; An existing `Buffer` to copy data from
+
+Copies the passed `buffer` data onto a new `Buffer` instance.
+
+### bufferFrom(string[, encoding])
+
+- `string` &lt;String&gt; A string to encode.
+- `encoding` &lt;String&gt; The encoding of `string`. **Default:** `'utf8'`
+
+Creates a new `Buffer` containing the given JavaScript string `string`. If
+provided, the `encoding` parameter identifies the character encoding of
+`string`.
+
+## See also
+
+- [buffer-alloc](https://github.com/LinusU/buffer-alloc) A ponyfill for `Buffer.alloc`
+- [buffer-alloc-unsafe](https://github.com/LinusU/buffer-alloc-unsafe) A ponyfill for `Buffer.allocUnsafe`

+ 5 - 0
node_modules/busboy/.eslintrc.js

@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = {
+  extends: '@mscdex/eslint-config',
+};

+ 24 - 0
node_modules/busboy/.github/workflows/ci.yml

@@ -0,0 +1,24 @@
+name: CI
+
+on:
+  pull_request:
+  push:
+    branches: [ master ]
+
+jobs:
+  tests-linux:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        node-version: [10.16.0, 10.x, 12.x, 14.x, 16.x]
+    steps:
+      - uses: actions/checkout@v2
+      - name: Use Node.js ${{ matrix.node-version }}
+        uses: actions/setup-node@v1
+        with:
+          node-version: ${{ matrix.node-version }}
+      - name: Install module
+        run: npm install
+      - name: Run tests
+        run: npm test

+ 23 - 0
node_modules/busboy/.github/workflows/lint.yml

@@ -0,0 +1,23 @@
+name: lint
+
+on:
+  pull_request:
+  push:
+    branches: [ master ]
+
+env:
+  NODE_VERSION: 16.x
+
+jobs:
+  lint-js:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Use Node.js ${{ env.NODE_VERSION }}
+        uses: actions/setup-node@v1
+        with:
+          node-version: ${{ env.NODE_VERSION }}
+      - name: Install ESLint + ESLint configs/plugins
+        run: npm install --only=dev
+      - name: Lint files
+        run: npm run lint

+ 19 - 0
node_modules/busboy/LICENSE

@@ -0,0 +1,19 @@
+Copyright Brian White. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.

+ 191 - 0
node_modules/busboy/README.md

@@ -0,0 +1,191 @@
+# Description
+
+A node.js module for parsing incoming HTML form data.
+
+Changes (breaking or otherwise) in v1.0.0 can be found [here](https://github.com/mscdex/busboy/issues/266).
+
+# Requirements
+
+* [node.js](http://nodejs.org/) -- v10.16.0 or newer
+
+
+# Install
+
+    npm install busboy
+
+
+# Examples
+
+* Parsing (multipart) with default options:
+
+```js
+const http = require('http');
+
+const busboy = require('busboy');
+
+http.createServer((req, res) => {
+  if (req.method === 'POST') {
+    console.log('POST request');
+    const bb = busboy({ headers: req.headers });
+    bb.on('file', (name, file, info) => {
+      const { filename, encoding, mimeType } = info;
+      console.log(
+        `File [${name}]: filename: %j, encoding: %j, mimeType: %j`,
+        filename,
+        encoding,
+        mimeType
+      );
+      file.on('data', (data) => {
+        console.log(`File [${name}] got ${data.length} bytes`);
+      }).on('close', () => {
+        console.log(`File [${name}] done`);
+      });
+    });
+    bb.on('field', (name, val, info) => {
+      console.log(`Field [${name}]: value: %j`, val);
+    });
+    bb.on('close', () => {
+      console.log('Done parsing form!');
+      res.writeHead(303, { Connection: 'close', Location: '/' });
+      res.end();
+    });
+    req.pipe(bb);
+  } else if (req.method === 'GET') {
+    res.writeHead(200, { Connection: 'close' });
+    res.end(`
+      <html>
+        <head></head>
+        <body>
+          <form method="POST" enctype="multipart/form-data">
+            <input type="file" name="filefield"><br />
+            <input type="text" name="textfield"><br />
+            <input type="submit">
+          </form>
+        </body>
+      </html>
+    `);
+  }
+}).listen(8000, () => {
+  console.log('Listening for requests');
+});
+
+// Example output:
+//
+// Listening for requests
+//   < ... form submitted ... >
+// POST request
+// File [filefield]: filename: "logo.jpg", encoding: "binary", mime: "image/jpeg"
+// File [filefield] got 11912 bytes
+// Field [textfield]: value: "testing! :-)"
+// File [filefield] done
+// Done parsing form!
+```
+
+* Save all incoming files to disk:
+
+```js
+const { randomFillSync } = require('crypto');
+const fs = require('fs');
+const http = require('http');
+const os = require('os');
+const path = require('path');
+
+const busboy = require('busboy');
+
+const random = (() => {
+  const buf = Buffer.alloc(16);
+  return () => randomFillSync(buf).toString('hex');
+})();
+
+http.createServer((req, res) => {
+  if (req.method === 'POST') {
+    const bb = busboy({ headers: req.headers });
+    bb.on('file', (name, file, info) => {
+      const saveTo = path.join(os.tmpdir(), `busboy-upload-${random()}`);
+      file.pipe(fs.createWriteStream(saveTo));
+    });
+    bb.on('close', () => {
+      res.writeHead(200, { 'Connection': 'close' });
+      res.end(`That's all folks!`);
+    });
+    req.pipe(bb);
+    return;
+  }
+  res.writeHead(404);
+  res.end();
+}).listen(8000, () => {
+  console.log('Listening for requests');
+});
+```
+
+
+# API
+
+## Exports
+
+`busboy` exports a single function:
+
+**( _function_ )**(< _object_ >config) - Creates and returns a new _Writable_ form parser stream.
+
+* Valid `config` properties:
+
+    * **headers** - _object_ - These are the HTTP headers of the incoming request, which are used by individual parsers.
+
+    * **highWaterMark** - _integer_ - highWaterMark to use for the parser stream. **Default:** node's _stream.Writable_ default.
+
+    * **fileHwm** - _integer_ - highWaterMark to use for individual file streams. **Default:** node's _stream.Readable_ default.
+
+    * **defCharset** - _string_ - Default character set to use when one isn't defined. **Default:** `'utf8'`.
+
+    * **defParamCharset** - _string_ - For multipart forms, the default character set to use for values of part header parameters (e.g. filename) that are not extended parameters (that contain an explicit charset). **Default:** `'latin1'`.
+
+    * **preservePath** - _boolean_ - If paths in filenames from file parts in a `'multipart/form-data'` request shall be preserved. **Default:** `false`.
+
+    * **limits** - _object_ - Various limits on incoming data. Valid properties are:
+
+        * **fieldNameSize** - _integer_ - Max field name size (in bytes). **Default:** `100`.
+
+        * **fieldSize** - _integer_ - Max field value size (in bytes). **Default:** `1048576` (1MB).
+
+        * **fields** - _integer_ - Max number of non-file fields. **Default:** `Infinity`.
+
+        * **fileSize** - _integer_ - For multipart forms, the max file size (in bytes). **Default:** `Infinity`.
+
+        * **files** - _integer_ - For multipart forms, the max number of file fields. **Default:** `Infinity`.
+
+        * **parts** - _integer_ - For multipart forms, the max number of parts (fields + files). **Default:** `Infinity`.
+
+        * **headerPairs** - _integer_ - For multipart forms, the max number of header key-value pairs to parse. **Default:** `2000` (same as node's http module).
+
+This function can throw exceptions if there is something wrong with the values in `config`. For example, if the Content-Type in `headers` is missing entirely, is not a supported type, or is missing the boundary for `'multipart/form-data'` requests.
+
+## (Special) Parser stream events
+
+* **file**(< _string_ >name, < _Readable_ >stream, < _object_ >info) - Emitted for each new file found. `name` contains the form field name. `stream` is a _Readable_ stream containing the file's data. No transformations/conversions (e.g. base64 to raw binary) are done on the file's data. `info` contains the following properties:
+
+    * `filename` - _string_ - If supplied, this contains the file's filename. **WARNING:** You should almost _never_ use this value as-is (especially if you are using `preservePath: true` in your `config`) as it could contain malicious input. You are better off generating your own (safe) filenames, or at the very least using a hash of the filename.
+
+    * `encoding` - _string_ - The file's `'Content-Transfer-Encoding'` value.
+
+    * `mimeType` - _string_ - The file's `'Content-Type'` value.
+
+    **Note:** If you listen for this event, you should always consume the `stream` whether you care about its contents or not (you can simply do `stream.resume();` if you want to discard/skip the contents), otherwise the `'finish'`/`'close'` event will never fire on the busboy parser stream.
+    However, if you aren't accepting files, you can either simply not listen for the `'file'` event at all or set `limits.files` to `0`, and any/all files will be automatically skipped (these skipped files will still count towards any configured `limits.files` and `limits.parts` limits though).
+
+    **Note:** If a configured `limits.fileSize` limit was reached for a file, `stream` will both have a boolean property `truncated` set to `true` (best checked at the end of the stream) and emit a `'limit'` event to notify you when this happens.
+
+* **field**(< _string_ >name, < _string_ >value, < _object_ >info) - Emitted for each new non-file field found. `name` contains the form field name. `value` contains the string value of the field. `info` contains the following properties:
+
+    * `nameTruncated` - _boolean_ - Whether `name` was truncated or not (due to a configured `limits.fieldNameSize` limit)
+
+    * `valueTruncated` - _boolean_ - Whether `value` was truncated or not (due to a configured `limits.fieldSize` limit)
+
+    * `encoding` - _string_ - The field's `'Content-Transfer-Encoding'` value.
+
+    * `mimeType` - _string_ - The field's `'Content-Type'` value.
+
+* **partsLimit**() - Emitted when the configured `limits.parts` limit has been reached. No more `'file'` or `'field'` events will be emitted.
+
+* **filesLimit**() - Emitted when the configured `limits.files` limit has been reached. No more `'file'` events will be emitted.
+
+* **fieldsLimit**() - Emitted when the configured `limits.fields` limit has been reached. No more `'field'` events will be emitted.

+ 149 - 0
node_modules/busboy/bench/bench-multipart-fields-100mb-big.js

@@ -0,0 +1,149 @@
+'use strict';
+
+function createMultipartBuffers(boundary, sizes) {
+  const bufs = [];
+  for (let i = 0; i < sizes.length; ++i) {
+    const mb = sizes[i] * 1024 * 1024;
+    bufs.push(Buffer.from([
+      `--${boundary}`,
+      `content-disposition: form-data; name="field${i + 1}"`,
+      '',
+      '0'.repeat(mb),
+      '',
+    ].join('\r\n')));
+  }
+  bufs.push(Buffer.from([
+    `--${boundary}--`,
+    '',
+  ].join('\r\n')));
+  return bufs;
+}
+
+const boundary = '-----------------------------168072824752491622650073';
+const buffers = createMultipartBuffers(boundary, [
+  10,
+  10,
+  10,
+  20,
+  50,
+]);
+const calls = {
+  partBegin: 0,
+  headerField: 0,
+  headerValue: 0,
+  headerEnd: 0,
+  headersEnd: 0,
+  partData: 0,
+  partEnd: 0,
+  end: 0,
+};
+
+const moduleName = process.argv[2];
+switch (moduleName) {
+  case 'busboy': {
+    const busboy = require('busboy');
+
+    const parser = busboy({
+      limits: {
+        fieldSizeLimit: Infinity,
+      },
+      headers: {
+        'content-type': `multipart/form-data; boundary=${boundary}`,
+      },
+    });
+    parser.on('field', (name, val, info) => {
+      ++calls.partBegin;
+      ++calls.partData;
+      ++calls.partEnd;
+    }).on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+    break;
+  }
+
+  case 'formidable': {
+    const { MultipartParser } = require('formidable');
+
+    const parser = new MultipartParser();
+    parser.initWithBoundary(boundary);
+    parser.on('data', ({ name }) => {
+      ++calls[name];
+      if (name === 'end')
+        console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+
+    break;
+  }
+
+  case 'multiparty': {
+    const { Readable } = require('stream');
+
+    const { Form } = require('multiparty');
+
+    const form = new Form({
+      maxFieldsSize: Infinity,
+      maxFields: Infinity,
+      maxFilesSize: Infinity,
+      autoFields: false,
+      autoFiles: false,
+    });
+
+    const req = new Readable({ read: () => {} });
+    req.headers = {
+      'content-type': `multipart/form-data; boundary=${boundary}`,
+    };
+
+    function hijack(name, fn) {
+      const oldFn = form[name];
+      form[name] = function() {
+        fn();
+        return oldFn.apply(this, arguments);
+      };
+    }
+
+    hijack('onParseHeaderField', () => {
+      ++calls.headerField;
+    });
+    hijack('onParseHeaderValue', () => {
+      ++calls.headerValue;
+    });
+    hijack('onParsePartBegin', () => {
+      ++calls.partBegin;
+    });
+    hijack('onParsePartData', () => {
+      ++calls.partData;
+    });
+    hijack('onParsePartEnd', () => {
+      ++calls.partEnd;
+    });
+
+    form.on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    }).on('part', (p) => p.resume());
+
+    console.time(moduleName);
+    form.parse(req);
+    for (const buf of buffers)
+      req.push(buf);
+    req.push(null);
+
+    break;
+  }
+
+  default:
+    if (moduleName === undefined)
+      console.error('Missing parser module name');
+    else
+      console.error(`Invalid parser module name: ${moduleName}`);
+    process.exit(1);
+}

+ 143 - 0
node_modules/busboy/bench/bench-multipart-fields-100mb-small.js

@@ -0,0 +1,143 @@
+'use strict';
+
+function createMultipartBuffers(boundary, sizes) {
+  const bufs = [];
+  for (let i = 0; i < sizes.length; ++i) {
+    const mb = sizes[i] * 1024 * 1024;
+    bufs.push(Buffer.from([
+      `--${boundary}`,
+      `content-disposition: form-data; name="field${i + 1}"`,
+      '',
+      '0'.repeat(mb),
+      '',
+    ].join('\r\n')));
+  }
+  bufs.push(Buffer.from([
+    `--${boundary}--`,
+    '',
+  ].join('\r\n')));
+  return bufs;
+}
+
+const boundary = '-----------------------------168072824752491622650073';
+const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
+const calls = {
+  partBegin: 0,
+  headerField: 0,
+  headerValue: 0,
+  headerEnd: 0,
+  headersEnd: 0,
+  partData: 0,
+  partEnd: 0,
+  end: 0,
+};
+
+const moduleName = process.argv[2];
+switch (moduleName) {
+  case 'busboy': {
+    const busboy = require('busboy');
+
+    const parser = busboy({
+      limits: {
+        fieldSizeLimit: Infinity,
+      },
+      headers: {
+        'content-type': `multipart/form-data; boundary=${boundary}`,
+      },
+    });
+    parser.on('field', (name, val, info) => {
+      ++calls.partBegin;
+      ++calls.partData;
+      ++calls.partEnd;
+    }).on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+    break;
+  }
+
+  case 'formidable': {
+    const { MultipartParser } = require('formidable');
+
+    const parser = new MultipartParser();
+    parser.initWithBoundary(boundary);
+    parser.on('data', ({ name }) => {
+      ++calls[name];
+      if (name === 'end')
+        console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+
+    break;
+  }
+
+  case 'multiparty': {
+    const { Readable } = require('stream');
+
+    const { Form } = require('multiparty');
+
+    const form = new Form({
+      maxFieldsSize: Infinity,
+      maxFields: Infinity,
+      maxFilesSize: Infinity,
+      autoFields: false,
+      autoFiles: false,
+    });
+
+    const req = new Readable({ read: () => {} });
+    req.headers = {
+      'content-type': `multipart/form-data; boundary=${boundary}`,
+    };
+
+    function hijack(name, fn) {
+      const oldFn = form[name];
+      form[name] = function() {
+        fn();
+        return oldFn.apply(this, arguments);
+      };
+    }
+
+    hijack('onParseHeaderField', () => {
+      ++calls.headerField;
+    });
+    hijack('onParseHeaderValue', () => {
+      ++calls.headerValue;
+    });
+    hijack('onParsePartBegin', () => {
+      ++calls.partBegin;
+    });
+    hijack('onParsePartData', () => {
+      ++calls.partData;
+    });
+    hijack('onParsePartEnd', () => {
+      ++calls.partEnd;
+    });
+
+    form.on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    }).on('part', (p) => p.resume());
+
+    console.time(moduleName);
+    form.parse(req);
+    for (const buf of buffers)
+      req.push(buf);
+    req.push(null);
+
+    break;
+  }
+
+  default:
+    if (moduleName === undefined)
+      console.error('Missing parser module name');
+    else
+      console.error(`Invalid parser module name: ${moduleName}`);
+    process.exit(1);
+}

+ 154 - 0
node_modules/busboy/bench/bench-multipart-files-100mb-big.js

@@ -0,0 +1,154 @@
+'use strict';
+
+function createMultipartBuffers(boundary, sizes) {
+  const bufs = [];
+  for (let i = 0; i < sizes.length; ++i) {
+    const mb = sizes[i] * 1024 * 1024;
+    bufs.push(Buffer.from([
+      `--${boundary}`,
+      `content-disposition: form-data; name="file${i + 1}"; `
+        + `filename="random${i + 1}.bin"`,
+      'content-type: application/octet-stream',
+      '',
+      '0'.repeat(mb),
+      '',
+    ].join('\r\n')));
+  }
+  bufs.push(Buffer.from([
+    `--${boundary}--`,
+    '',
+  ].join('\r\n')));
+  return bufs;
+}
+
+const boundary = '-----------------------------168072824752491622650073';
+const buffers = createMultipartBuffers(boundary, [
+  10,
+  10,
+  10,
+  20,
+  50,
+]);
+const calls = {
+  partBegin: 0,
+  headerField: 0,
+  headerValue: 0,
+  headerEnd: 0,
+  headersEnd: 0,
+  partData: 0,
+  partEnd: 0,
+  end: 0,
+};
+
+const moduleName = process.argv[2];
+switch (moduleName) {
+  case 'busboy': {
+    const busboy = require('busboy');
+
+    const parser = busboy({
+      limits: {
+        fieldSizeLimit: Infinity,
+      },
+      headers: {
+        'content-type': `multipart/form-data; boundary=${boundary}`,
+      },
+    });
+    parser.on('file', (name, stream, info) => {
+      ++calls.partBegin;
+      stream.on('data', (chunk) => {
+        ++calls.partData;
+      }).on('end', () => {
+        ++calls.partEnd;
+      });
+    }).on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+    break;
+  }
+
+  case 'formidable': {
+    const { MultipartParser } = require('formidable');
+
+    const parser = new MultipartParser();
+    parser.initWithBoundary(boundary);
+    parser.on('data', ({ name }) => {
+      ++calls[name];
+      if (name === 'end')
+        console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+
+    break;
+  }
+
+  case 'multiparty': {
+    const { Readable } = require('stream');
+
+    const { Form } = require('multiparty');
+
+    const form = new Form({
+      maxFieldsSize: Infinity,
+      maxFields: Infinity,
+      maxFilesSize: Infinity,
+      autoFields: false,
+      autoFiles: false,
+    });
+
+    const req = new Readable({ read: () => {} });
+    req.headers = {
+      'content-type': `multipart/form-data; boundary=${boundary}`,
+    };
+
+    function hijack(name, fn) {
+      const oldFn = form[name];
+      form[name] = function() {
+        fn();
+        return oldFn.apply(this, arguments);
+      };
+    }
+
+    hijack('onParseHeaderField', () => {
+      ++calls.headerField;
+    });
+    hijack('onParseHeaderValue', () => {
+      ++calls.headerValue;
+    });
+    hijack('onParsePartBegin', () => {
+      ++calls.partBegin;
+    });
+    hijack('onParsePartData', () => {
+      ++calls.partData;
+    });
+    hijack('onParsePartEnd', () => {
+      ++calls.partEnd;
+    });
+
+    form.on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    }).on('part', (p) => p.resume());
+
+    console.time(moduleName);
+    form.parse(req);
+    for (const buf of buffers)
+      req.push(buf);
+    req.push(null);
+
+    break;
+  }
+
+  default:
+    if (moduleName === undefined)
+      console.error('Missing parser module name');
+    else
+      console.error(`Invalid parser module name: ${moduleName}`);
+    process.exit(1);
+}

+ 148 - 0
node_modules/busboy/bench/bench-multipart-files-100mb-small.js

@@ -0,0 +1,148 @@
+'use strict';
+
+function createMultipartBuffers(boundary, sizes) {
+  const bufs = [];
+  for (let i = 0; i < sizes.length; ++i) {
+    const mb = sizes[i] * 1024 * 1024;
+    bufs.push(Buffer.from([
+      `--${boundary}`,
+      `content-disposition: form-data; name="file${i + 1}"; `
+        + `filename="random${i + 1}.bin"`,
+      'content-type: application/octet-stream',
+      '',
+      '0'.repeat(mb),
+      '',
+    ].join('\r\n')));
+  }
+  bufs.push(Buffer.from([
+    `--${boundary}--`,
+    '',
+  ].join('\r\n')));
+  return bufs;
+}
+
+const boundary = '-----------------------------168072824752491622650073';
+const buffers = createMultipartBuffers(boundary, (new Array(100)).fill(1));
+const calls = {
+  partBegin: 0,
+  headerField: 0,
+  headerValue: 0,
+  headerEnd: 0,
+  headersEnd: 0,
+  partData: 0,
+  partEnd: 0,
+  end: 0,
+};
+
+const moduleName = process.argv[2];
+switch (moduleName) {
+  case 'busboy': {
+    const busboy = require('busboy');
+
+    const parser = busboy({
+      limits: {
+        fieldSizeLimit: Infinity,
+      },
+      headers: {
+        'content-type': `multipart/form-data; boundary=${boundary}`,
+      },
+    });
+    parser.on('file', (name, stream, info) => {
+      ++calls.partBegin;
+      stream.on('data', (chunk) => {
+        ++calls.partData;
+      }).on('end', () => {
+        ++calls.partEnd;
+      });
+    }).on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+    break;
+  }
+
+  case 'formidable': {
+    const { MultipartParser } = require('formidable');
+
+    const parser = new MultipartParser();
+    parser.initWithBoundary(boundary);
+    parser.on('data', ({ name }) => {
+      ++calls[name];
+      if (name === 'end')
+        console.timeEnd(moduleName);
+    });
+
+    console.time(moduleName);
+    for (const buf of buffers)
+      parser.write(buf);
+
+    break;
+  }
+
+  case 'multiparty': {
+    const { Readable } = require('stream');
+
+    const { Form } = require('multiparty');
+
+    const form = new Form({
+      maxFieldsSize: Infinity,
+      maxFields: Infinity,
+      maxFilesSize: Infinity,
+      autoFields: false,
+      autoFiles: false,
+    });
+
+    const req = new Readable({ read: () => {} });
+    req.headers = {
+      'content-type': `multipart/form-data; boundary=${boundary}`,
+    };
+
+    function hijack(name, fn) {
+      const oldFn = form[name];
+      form[name] = function() {
+        fn();
+        return oldFn.apply(this, arguments);
+      };
+    }
+
+    hijack('onParseHeaderField', () => {
+      ++calls.headerField;
+    });
+    hijack('onParseHeaderValue', () => {
+      ++calls.headerValue;
+    });
+    hijack('onParsePartBegin', () => {
+      ++calls.partBegin;
+    });
+    hijack('onParsePartData', () => {
+      ++calls.partData;
+    });
+    hijack('onParsePartEnd', () => {
+      ++calls.partEnd;
+    });
+
+    form.on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    }).on('part', (p) => p.resume());
+
+    console.time(moduleName);
+    form.parse(req);
+    for (const buf of buffers)
+      req.push(buf);
+    req.push(null);
+
+    break;
+  }
+
+  default:
+    if (moduleName === undefined)
+      console.error('Missing parser module name');
+    else
+      console.error(`Invalid parser module name: ${moduleName}`);
+    process.exit(1);
+}

+ 101 - 0
node_modules/busboy/bench/bench-urlencoded-fields-100pairs-small.js

@@ -0,0 +1,101 @@
+'use strict';
+
+const buffers = [
+  Buffer.from(
+    (new Array(100)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
+  ),
+];
+const calls = {
+  field: 0,
+  end: 0,
+};
+
+let n = 3e3;
+
+const moduleName = process.argv[2];
+switch (moduleName) {
+  case 'busboy': {
+    const busboy = require('busboy');
+
+    console.time(moduleName);
+    (function next() {
+      const parser = busboy({
+        limits: {
+          fieldSizeLimit: Infinity,
+        },
+        headers: {
+          'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
+        },
+      });
+      parser.on('field', (name, val, info) => {
+        ++calls.field;
+      }).on('close', () => {
+        ++calls.end;
+        if (--n === 0)
+          console.timeEnd(moduleName);
+        else
+          process.nextTick(next);
+      });
+
+      for (const buf of buffers)
+        parser.write(buf);
+      parser.end();
+    })();
+    break;
+  }
+
+  case 'formidable': {
+    const QuerystringParser =
+      require('formidable/src/parsers/Querystring.js');
+
+    console.time(moduleName);
+    (function next() {
+      const parser = new QuerystringParser();
+      parser.on('data', (obj) => {
+        ++calls.field;
+      }).on('end', () => {
+        ++calls.end;
+        if (--n === 0)
+          console.timeEnd(moduleName);
+        else
+          process.nextTick(next);
+      });
+
+      for (const buf of buffers)
+        parser.write(buf);
+      parser.end();
+    })();
+    break;
+  }
+
+  case 'formidable-streaming': {
+    const QuerystringParser =
+      require('formidable/src/parsers/StreamingQuerystring.js');
+
+    console.time(moduleName);
+    (function next() {
+      const parser = new QuerystringParser();
+      parser.on('data', (obj) => {
+        ++calls.field;
+      }).on('end', () => {
+        ++calls.end;
+        if (--n === 0)
+          console.timeEnd(moduleName);
+        else
+          process.nextTick(next);
+      });
+
+      for (const buf of buffers)
+        parser.write(buf);
+      parser.end();
+    })();
+    break;
+  }
+
+  default:
+    if (moduleName === undefined)
+      console.error('Missing parser module name');
+    else
+      console.error(`Invalid parser module name: ${moduleName}`);
+    process.exit(1);
+}

+ 84 - 0
node_modules/busboy/bench/bench-urlencoded-fields-900pairs-small-alt.js

@@ -0,0 +1,84 @@
+'use strict';
+
+const buffers = [
+  Buffer.from(
+    (new Array(900)).fill('').map((_, i) => `key${i}=value${i}`).join('&')
+  ),
+];
+const calls = {
+  field: 0,
+  end: 0,
+};
+
+const moduleName = process.argv[2];
+switch (moduleName) {
+  case 'busboy': {
+    const busboy = require('busboy');
+
+    console.time(moduleName);
+    const parser = busboy({
+      limits: {
+        fieldSizeLimit: Infinity,
+      },
+      headers: {
+        'content-type': 'application/x-www-form-urlencoded; charset=utf-8',
+      },
+    });
+    parser.on('field', (name, val, info) => {
+      ++calls.field;
+    }).on('close', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    for (const buf of buffers)
+      parser.write(buf);
+    parser.end();
+    break;
+  }
+
+  case 'formidable': {
+    const QuerystringParser =
+      require('formidable/src/parsers/Querystring.js');
+
+    console.time(moduleName);
+    const parser = new QuerystringParser();
+    parser.on('data', (obj) => {
+      ++calls.field;
+    }).on('end', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    for (const buf of buffers)
+      parser.write(buf);
+    parser.end();
+    break;
+  }
+
+  case 'formidable-streaming': {
+    const QuerystringParser =
+      require('formidable/src/parsers/StreamingQuerystring.js');
+
+    console.time(moduleName);
+    const parser = new QuerystringParser();
+    parser.on('data', (obj) => {
+      ++calls.field;
+    }).on('end', () => {
+      ++calls.end;
+      console.timeEnd(moduleName);
+    });
+
+    for (const buf of buffers)
+      parser.write(buf);
+    parser.end();
+    break;
+  }
+
+  default:
+    if (moduleName === undefined)
+      console.error('Missing parser module name');
+    else
+      console.error(`Invalid parser module name: ${moduleName}`);
+    process.exit(1);
+}

+ 57 - 0
node_modules/busboy/lib/index.js

@@ -0,0 +1,57 @@
+'use strict';
+
+const { parseContentType } = require('./utils.js');
+
+function getInstance(cfg) {
+  const headers = cfg.headers;
+  const conType = parseContentType(headers['content-type']);
+  if (!conType)
+    throw new Error('Malformed content type');
+
+  for (const type of TYPES) {
+    const matched = type.detect(conType);
+    if (!matched)
+      continue;
+
+    const instanceCfg = {
+      limits: cfg.limits,
+      headers,
+      conType,
+      highWaterMark: undefined,
+      fileHwm: undefined,
+      defCharset: undefined,
+      defParamCharset: undefined,
+      preservePath: false,
+    };
+    if (cfg.highWaterMark)
+      instanceCfg.highWaterMark = cfg.highWaterMark;
+    if (cfg.fileHwm)
+      instanceCfg.fileHwm = cfg.fileHwm;
+    instanceCfg.defCharset = cfg.defCharset;
+    instanceCfg.defParamCharset = cfg.defParamCharset;
+    instanceCfg.preservePath = cfg.preservePath;
+    return new type(instanceCfg);
+  }
+
+  throw new Error(`Unsupported content type: ${headers['content-type']}`);
+}
+
+// Note: types are explicitly listed here for easier bundling
+// See: https://github.com/mscdex/busboy/issues/121
+const TYPES = [
+  require('./types/multipart'),
+  require('./types/urlencoded'),
+].filter(function(typemod) { return typeof typemod.detect === 'function'; });
+
+module.exports = (cfg) => {
+  if (typeof cfg !== 'object' || cfg === null)
+    cfg = {};
+
+  if (typeof cfg.headers !== 'object'
+      || cfg.headers === null
+      || typeof cfg.headers['content-type'] !== 'string') {
+    throw new Error('Missing Content-Type');
+  }
+
+  return getInstance(cfg);
+};

+ 653 - 0
node_modules/busboy/lib/types/multipart.js

@@ -0,0 +1,653 @@
+'use strict';
+
+const { Readable, Writable } = require('stream');
+
+const StreamSearch = require('streamsearch');
+
+const {
+  basename,
+  convertToUTF8,
+  getDecoder,
+  parseContentType,
+  parseDisposition,
+} = require('../utils.js');
+
+const BUF_CRLF = Buffer.from('\r\n');
+const BUF_CR = Buffer.from('\r');
+const BUF_DASH = Buffer.from('-');
+
+function noop() {}
+
+const MAX_HEADER_PAIRS = 2000; // From node
+const MAX_HEADER_SIZE = 16 * 1024; // From node (its default value)
+
+const HPARSER_NAME = 0;
+const HPARSER_PRE_OWS = 1;
+const HPARSER_VALUE = 2;
+class HeaderParser {
+  constructor(cb) {
+    this.header = Object.create(null);
+    this.pairCount = 0;
+    this.byteCount = 0;
+    this.state = HPARSER_NAME;
+    this.name = '';
+    this.value = '';
+    this.crlf = 0;
+    this.cb = cb;
+  }
+
+  reset() {
+    this.header = Object.create(null);
+    this.pairCount = 0;
+    this.byteCount = 0;
+    this.state = HPARSER_NAME;
+    this.name = '';
+    this.value = '';
+    this.crlf = 0;
+  }
+
+  push(chunk, pos, end) {
+    let start = pos;
+    while (pos < end) {
+      switch (this.state) {
+        case HPARSER_NAME: {
+          let done = false;
+          for (; pos < end; ++pos) {
+            if (this.byteCount === MAX_HEADER_SIZE)
+              return -1;
+            ++this.byteCount;
+            const code = chunk[pos];
+            if (TOKEN[code] !== 1) {
+              if (code !== 58/* ':' */)
+                return -1;
+              this.name += chunk.latin1Slice(start, pos);
+              if (this.name.length === 0)
+                return -1;
+              ++pos;
+              done = true;
+              this.state = HPARSER_PRE_OWS;
+              break;
+            }
+          }
+          if (!done) {
+            this.name += chunk.latin1Slice(start, pos);
+            break;
+          }
+          // FALLTHROUGH
+        }
+        case HPARSER_PRE_OWS: {
+          // Skip optional whitespace
+          let done = false;
+          for (; pos < end; ++pos) {
+            if (this.byteCount === MAX_HEADER_SIZE)
+              return -1;
+            ++this.byteCount;
+            const code = chunk[pos];
+            if (code !== 32/* ' ' */ && code !== 9/* '\t' */) {
+              start = pos;
+              done = true;
+              this.state = HPARSER_VALUE;
+              break;
+            }
+          }
+          if (!done)
+            break;
+          // FALLTHROUGH
+        }
+        case HPARSER_VALUE:
+          switch (this.crlf) {
+            case 0: // Nothing yet
+              for (; pos < end; ++pos) {
+                if (this.byteCount === MAX_HEADER_SIZE)
+                  return -1;
+                ++this.byteCount;
+                const code = chunk[pos];
+                if (FIELD_VCHAR[code] !== 1) {
+                  if (code !== 13/* '\r' */)
+                    return -1;
+                  ++this.crlf;
+                  break;
+                }
+              }
+              this.value += chunk.latin1Slice(start, pos++);
+              break;
+            case 1: // Received CR
+              if (this.byteCount === MAX_HEADER_SIZE)
+                return -1;
+              ++this.byteCount;
+              if (chunk[pos++] !== 10/* '\n' */)
+                return -1;
+              ++this.crlf;
+              break;
+            case 2: { // Received CR LF
+              if (this.byteCount === MAX_HEADER_SIZE)
+                return -1;
+              ++this.byteCount;
+              const code = chunk[pos];
+              if (code === 32/* ' ' */ || code === 9/* '\t' */) {
+                // Folded value
+                start = pos;
+                this.crlf = 0;
+              } else {
+                if (++this.pairCount < MAX_HEADER_PAIRS) {
+                  this.name = this.name.toLowerCase();
+                  if (this.header[this.name] === undefined)
+                    this.header[this.name] = [this.value];
+                  else
+                    this.header[this.name].push(this.value);
+                }
+                if (code === 13/* '\r' */) {
+                  ++this.crlf;
+                  ++pos;
+                } else {
+                  // Assume start of next header field name
+                  start = pos;
+                  this.crlf = 0;
+                  this.state = HPARSER_NAME;
+                  this.name = '';
+                  this.value = '';
+                }
+              }
+              break;
+            }
+            case 3: { // Received CR LF CR
+              if (this.byteCount === MAX_HEADER_SIZE)
+                return -1;
+              ++this.byteCount;
+              if (chunk[pos++] !== 10/* '\n' */)
+                return -1;
+              // End of header
+              const header = this.header;
+              this.reset();
+              this.cb(header);
+              return pos;
+            }
+          }
+          break;
+      }
+    }
+
+    return pos;
+  }
+}
+
+class FileStream extends Readable {
+  constructor(opts, owner) {
+    super(opts);
+    this.truncated = false;
+    this._readcb = null;
+    this.once('end', () => {
+      // We need to make sure that we call any outstanding _writecb() that is
+      // associated with this file so that processing of the rest of the form
+      // can continue. This may not happen if the file stream ends right after
+      // backpressure kicks in, so we force it here.
+      this._read();
+      if (--owner._fileEndsLeft === 0 && owner._finalcb) {
+        const cb = owner._finalcb;
+        owner._finalcb = null;
+        // Make sure other 'end' event handlers get a chance to be executed
+        // before busboy's 'finish' event is emitted
+        process.nextTick(cb);
+      }
+    });
+  }
+  _read(n) {
+    const cb = this._readcb;
+    if (cb) {
+      this._readcb = null;
+      cb();
+    }
+  }
+}
+
+const ignoreData = {
+  push: (chunk, pos) => {},
+  destroy: () => {},
+};
+
+function callAndUnsetCb(self, err) {
+  const cb = self._writecb;
+  self._writecb = null;
+  if (err)
+    self.destroy(err);
+  else if (cb)
+    cb();
+}
+
+function nullDecoder(val, hint) {
+  return val;
+}
+
+class Multipart extends Writable {
+  constructor(cfg) {
+    const streamOpts = {
+      autoDestroy: true,
+      emitClose: true,
+      highWaterMark: (typeof cfg.highWaterMark === 'number'
+                      ? cfg.highWaterMark
+                      : undefined),
+    };
+    super(streamOpts);
+
+    if (!cfg.conType.params || typeof cfg.conType.params.boundary !== 'string')
+      throw new Error('Multipart: Boundary not found');
+
+    const boundary = cfg.conType.params.boundary;
+    const paramDecoder = (typeof cfg.defParamCharset === 'string'
+                            && cfg.defParamCharset
+                          ? getDecoder(cfg.defParamCharset)
+                          : nullDecoder);
+    const defCharset = (cfg.defCharset || 'utf8');
+    const preservePath = cfg.preservePath;
+    const fileOpts = {
+      autoDestroy: true,
+      emitClose: true,
+      highWaterMark: (typeof cfg.fileHwm === 'number'
+                      ? cfg.fileHwm
+                      : undefined),
+    };
+
+    const limits = cfg.limits;
+    const fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
+                            ? limits.fieldSize
+                            : 1 * 1024 * 1024);
+    const fileSizeLimit = (limits && typeof limits.fileSize === 'number'
+                           ? limits.fileSize
+                           : Infinity);
+    const filesLimit = (limits && typeof limits.files === 'number'
+                        ? limits.files
+                        : Infinity);
+    const fieldsLimit = (limits && typeof limits.fields === 'number'
+                         ? limits.fields
+                         : Infinity);
+    const partsLimit = (limits && typeof limits.parts === 'number'
+                        ? limits.parts
+                        : Infinity);
+
+    let parts = -1; // Account for initial boundary
+    let fields = 0;
+    let files = 0;
+    let skipPart = false;
+
+    this._fileEndsLeft = 0;
+    this._fileStream = undefined;
+    this._complete = false;
+    let fileSize = 0;
+
+    let field;
+    let fieldSize = 0;
+    let partCharset;
+    let partEncoding;
+    let partType;
+    let partName;
+    let partTruncated = false;
+
+    let hitFilesLimit = false;
+    let hitFieldsLimit = false;
+
+    this._hparser = null;
+    const hparser = new HeaderParser((header) => {
+      this._hparser = null;
+      skipPart = false;
+
+      partType = 'text/plain';
+      partCharset = defCharset;
+      partEncoding = '7bit';
+      partName = undefined;
+      partTruncated = false;
+
+      let filename;
+      if (!header['content-disposition']) {
+        skipPart = true;
+        return;
+      }
+
+      const disp = parseDisposition(header['content-disposition'][0],
+                                    paramDecoder);
+      if (!disp || disp.type !== 'form-data') {
+        skipPart = true;
+        return;
+      }
+
+      if (disp.params) {
+        if (disp.params.name)
+          partName = disp.params.name;
+
+        if (disp.params['filename*'])
+          filename = disp.params['filename*'];
+        else if (disp.params.filename)
+          filename = disp.params.filename;
+
+        if (filename !== undefined && !preservePath)
+          filename = basename(filename);
+      }
+
+      if (header['content-type']) {
+        const conType = parseContentType(header['content-type'][0]);
+        if (conType) {
+          partType = `${conType.type}/${conType.subtype}`;
+          if (conType.params && typeof conType.params.charset === 'string')
+            partCharset = conType.params.charset.toLowerCase();
+        }
+      }
+
+      if (header['content-transfer-encoding'])
+        partEncoding = header['content-transfer-encoding'][0].toLowerCase();
+
+      if (partType === 'application/octet-stream' || filename !== undefined) {
+        // File
+
+        if (files === filesLimit) {
+          if (!hitFilesLimit) {
+            hitFilesLimit = true;
+            this.emit('filesLimit');
+          }
+          skipPart = true;
+          return;
+        }
+        ++files;
+
+        if (this.listenerCount('file') === 0) {
+          skipPart = true;
+          return;
+        }
+
+        fileSize = 0;
+        this._fileStream = new FileStream(fileOpts, this);
+        ++this._fileEndsLeft;
+        this.emit(
+          'file',
+          partName,
+          this._fileStream,
+          { filename,
+            encoding: partEncoding,
+            mimeType: partType }
+        );
+      } else {
+        // Non-file
+
+        if (fields === fieldsLimit) {
+          if (!hitFieldsLimit) {
+            hitFieldsLimit = true;
+            this.emit('fieldsLimit');
+          }
+          skipPart = true;
+          return;
+        }
+        ++fields;
+
+        if (this.listenerCount('field') === 0) {
+          skipPart = true;
+          return;
+        }
+
+        field = [];
+        fieldSize = 0;
+      }
+    });
+
+    let matchPostBoundary = 0;
+    const ssCb = (isMatch, data, start, end, isDataSafe) => {
+retrydata:
+      while (data) {
+        if (this._hparser !== null) {
+          const ret = this._hparser.push(data, start, end);
+          if (ret === -1) {
+            this._hparser = null;
+            hparser.reset();
+            this.emit('error', new Error('Malformed part header'));
+            break;
+          }
+          start = ret;
+        }
+
+        if (start === end)
+          break;
+
+        if (matchPostBoundary !== 0) {
+          if (matchPostBoundary === 1) {
+            switch (data[start]) {
+              case 45: // '-'
+                // Try matching '--' after boundary
+                matchPostBoundary = 2;
+                ++start;
+                break;
+              case 13: // '\r'
+                // Try matching CR LF before header
+                matchPostBoundary = 3;
+                ++start;
+                break;
+              default:
+                matchPostBoundary = 0;
+            }
+            if (start === end)
+              return;
+          }
+
+          if (matchPostBoundary === 2) {
+            matchPostBoundary = 0;
+            if (data[start] === 45/* '-' */) {
+              // End of multipart data
+              this._complete = true;
+              this._bparser = ignoreData;
+              return;
+            }
+            // We saw something other than '-', so put the dash we consumed
+            // "back"
+            const writecb = this._writecb;
+            this._writecb = noop;
+            ssCb(false, BUF_DASH, 0, 1, false);
+            this._writecb = writecb;
+          } else if (matchPostBoundary === 3) {
+            matchPostBoundary = 0;
+            if (data[start] === 10/* '\n' */) {
+              ++start;
+              if (parts >= partsLimit)
+                break;
+              // Prepare the header parser
+              this._hparser = hparser;
+              if (start === end)
+                break;
+              // Process the remaining data as a header
+              continue retrydata;
+            } else {
+              // We saw something other than LF, so put the CR we consumed
+              // "back"
+              const writecb = this._writecb;
+              this._writecb = noop;
+              ssCb(false, BUF_CR, 0, 1, false);
+              this._writecb = writecb;
+            }
+          }
+        }
+
+        if (!skipPart) {
+          if (this._fileStream) {
+            let chunk;
+            const actualLen = Math.min(end - start, fileSizeLimit - fileSize);
+            if (!isDataSafe) {
+              chunk = Buffer.allocUnsafe(actualLen);
+              data.copy(chunk, 0, start, start + actualLen);
+            } else {
+              chunk = data.slice(start, start + actualLen);
+            }
+
+            fileSize += chunk.length;
+            if (fileSize === fileSizeLimit) {
+              if (chunk.length > 0)
+                this._fileStream.push(chunk);
+              this._fileStream.emit('limit');
+              this._fileStream.truncated = true;
+              skipPart = true;
+            } else if (!this._fileStream.push(chunk)) {
+              if (this._writecb)
+                this._fileStream._readcb = this._writecb;
+              this._writecb = null;
+            }
+          } else if (field !== undefined) {
+            let chunk;
+            const actualLen = Math.min(
+              end - start,
+              fieldSizeLimit - fieldSize
+            );
+            if (!isDataSafe) {
+              chunk = Buffer.allocUnsafe(actualLen);
+              data.copy(chunk, 0, start, start + actualLen);
+            } else {
+              chunk = data.slice(start, start + actualLen);
+            }
+
+            fieldSize += actualLen;
+            field.push(chunk);
+            if (fieldSize === fieldSizeLimit) {
+              skipPart = true;
+              partTruncated = true;
+            }
+          }
+        }
+
+        break;
+      }
+
+      if (isMatch) {
+        matchPostBoundary = 1;
+
+        if (this._fileStream) {
+          // End the active file stream if the previous part was a file
+          this._fileStream.push(null);
+          this._fileStream = null;
+        } else if (field !== undefined) {
+          let data;
+          switch (field.length) {
+            case 0:
+              data = '';
+              break;
+            case 1:
+              data = convertToUTF8(field[0], partCharset, 0);
+              break;
+            default:
+              data = convertToUTF8(
+                Buffer.concat(field, fieldSize),
+                partCharset,
+                0
+              );
+          }
+          field = undefined;
+          fieldSize = 0;
+          this.emit(
+            'field',
+            partName,
+            data,
+            { nameTruncated: false,
+              valueTruncated: partTruncated,
+              encoding: partEncoding,
+              mimeType: partType }
+          );
+        }
+
+        if (++parts === partsLimit)
+          this.emit('partsLimit');
+      }
+    };
+    this._bparser = new StreamSearch(`\r\n--${boundary}`, ssCb);
+
+    this._writecb = null;
+    this._finalcb = null;
+
+    // Just in case there is no preamble
+    this.write(BUF_CRLF);
+  }
+
+  static detect(conType) {
+    return (conType.type === 'multipart' && conType.subtype === 'form-data');
+  }
+
+  _write(chunk, enc, cb) {
+    this._writecb = cb;
+    this._bparser.push(chunk, 0);
+    if (this._writecb)
+      callAndUnsetCb(this);
+  }
+
+  _destroy(err, cb) {
+    this._hparser = null;
+    this._bparser = ignoreData;
+    if (!err)
+      err = checkEndState(this);
+    const fileStream = this._fileStream;
+    if (fileStream) {
+      this._fileStream = null;
+      fileStream.destroy(err);
+    }
+    cb(err);
+  }
+
+  _final(cb) {
+    this._bparser.destroy();
+    if (!this._complete)
+      return cb(new Error('Unexpected end of form'));
+    if (this._fileEndsLeft)
+      this._finalcb = finalcb.bind(null, this, cb);
+    else
+      finalcb(this, cb);
+  }
+}
+
+function finalcb(self, cb, err) {
+  if (err)
+    return cb(err);
+  err = checkEndState(self);
+  cb(err);
+}
+
+function checkEndState(self) {
+  if (self._hparser)
+    return new Error('Malformed part header');
+  const fileStream = self._fileStream;
+  if (fileStream) {
+    self._fileStream = null;
+    fileStream.destroy(new Error('Unexpected end of file'));
+  }
+  if (!self._complete)
+    return new Error('Unexpected end of form');
+}
+
+const TOKEN = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+];
+
+const FIELD_VCHAR = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+];
+
+module.exports = Multipart;

+ 350 - 0
node_modules/busboy/lib/types/urlencoded.js

@@ -0,0 +1,350 @@
+'use strict';
+
+const { Writable } = require('stream');
+
+const { getDecoder } = require('../utils.js');
+
+class URLEncoded extends Writable {
+  constructor(cfg) {
+    const streamOpts = {
+      autoDestroy: true,
+      emitClose: true,
+      highWaterMark: (typeof cfg.highWaterMark === 'number'
+                      ? cfg.highWaterMark
+                      : undefined),
+    };
+    super(streamOpts);
+
+    let charset = (cfg.defCharset || 'utf8');
+    if (cfg.conType.params && typeof cfg.conType.params.charset === 'string')
+      charset = cfg.conType.params.charset;
+
+    this.charset = charset;
+
+    const limits = cfg.limits;
+    this.fieldSizeLimit = (limits && typeof limits.fieldSize === 'number'
+                           ? limits.fieldSize
+                           : 1 * 1024 * 1024);
+    this.fieldsLimit = (limits && typeof limits.fields === 'number'
+                        ? limits.fields
+                        : Infinity);
+    this.fieldNameSizeLimit = (
+      limits && typeof limits.fieldNameSize === 'number'
+      ? limits.fieldNameSize
+      : 100
+    );
+
+    this._inKey = true;
+    this._keyTrunc = false;
+    this._valTrunc = false;
+    this._bytesKey = 0;
+    this._bytesVal = 0;
+    this._fields = 0;
+    this._key = '';
+    this._val = '';
+    this._byte = -2;
+    this._lastPos = 0;
+    this._encode = 0;
+    this._decoder = getDecoder(charset);
+  }
+
+  static detect(conType) {
+    return (conType.type === 'application'
+            && conType.subtype === 'x-www-form-urlencoded');
+  }
+
+  _write(chunk, enc, cb) {
+    if (this._fields >= this.fieldsLimit)
+      return cb();
+
+    let i = 0;
+    const len = chunk.length;
+    this._lastPos = 0;
+
+    // Check if we last ended mid-percent-encoded byte
+    if (this._byte !== -2) {
+      i = readPctEnc(this, chunk, i, len);
+      if (i === -1)
+        return cb(new Error('Malformed urlencoded form'));
+      if (i >= len)
+        return cb();
+      if (this._inKey)
+        ++this._bytesKey;
+      else
+        ++this._bytesVal;
+    }
+
+main:
+    while (i < len) {
+      if (this._inKey) {
+        // Parsing key
+
+        i = skipKeyBytes(this, chunk, i, len);
+
+        while (i < len) {
+          switch (chunk[i]) {
+            case 61: // '='
+              if (this._lastPos < i)
+                this._key += chunk.latin1Slice(this._lastPos, i);
+              this._lastPos = ++i;
+              this._key = this._decoder(this._key, this._encode);
+              this._encode = 0;
+              this._inKey = false;
+              continue main;
+            case 38: // '&'
+              if (this._lastPos < i)
+                this._key += chunk.latin1Slice(this._lastPos, i);
+              this._lastPos = ++i;
+              this._key = this._decoder(this._key, this._encode);
+              this._encode = 0;
+              if (this._bytesKey > 0) {
+                this.emit(
+                  'field',
+                  this._key,
+                  '',
+                  { nameTruncated: this._keyTrunc,
+                    valueTruncated: false,
+                    encoding: this.charset,
+                    mimeType: 'text/plain' }
+                );
+              }
+              this._key = '';
+              this._val = '';
+              this._keyTrunc = false;
+              this._valTrunc = false;
+              this._bytesKey = 0;
+              this._bytesVal = 0;
+              if (++this._fields >= this.fieldsLimit) {
+                this.emit('fieldsLimit');
+                return cb();
+              }
+              continue;
+            case 43: // '+'
+              if (this._lastPos < i)
+                this._key += chunk.latin1Slice(this._lastPos, i);
+              this._key += ' ';
+              this._lastPos = i + 1;
+              break;
+            case 37: // '%'
+              if (this._encode === 0)
+                this._encode = 1;
+              if (this._lastPos < i)
+                this._key += chunk.latin1Slice(this._lastPos, i);
+              this._lastPos = i + 1;
+              this._byte = -1;
+              i = readPctEnc(this, chunk, i + 1, len);
+              if (i === -1)
+                return cb(new Error('Malformed urlencoded form'));
+              if (i >= len)
+                return cb();
+              ++this._bytesKey;
+              i = skipKeyBytes(this, chunk, i, len);
+              continue;
+          }
+          ++i;
+          ++this._bytesKey;
+          i = skipKeyBytes(this, chunk, i, len);
+        }
+        if (this._lastPos < i)
+          this._key += chunk.latin1Slice(this._lastPos, i);
+      } else {
+        // Parsing value
+
+        i = skipValBytes(this, chunk, i, len);
+
+        while (i < len) {
+          switch (chunk[i]) {
+            case 38: // '&'
+              if (this._lastPos < i)
+                this._val += chunk.latin1Slice(this._lastPos, i);
+              this._lastPos = ++i;
+              this._inKey = true;
+              this._val = this._decoder(this._val, this._encode);
+              this._encode = 0;
+              if (this._bytesKey > 0 || this._bytesVal > 0) {
+                this.emit(
+                  'field',
+                  this._key,
+                  this._val,
+                  { nameTruncated: this._keyTrunc,
+                    valueTruncated: this._valTrunc,
+                    encoding: this.charset,
+                    mimeType: 'text/plain' }
+                );
+              }
+              this._key = '';
+              this._val = '';
+              this._keyTrunc = false;
+              this._valTrunc = false;
+              this._bytesKey = 0;
+              this._bytesVal = 0;
+              if (++this._fields >= this.fieldsLimit) {
+                this.emit('fieldsLimit');
+                return cb();
+              }
+              continue main;
+            case 43: // '+'
+              if (this._lastPos < i)
+                this._val += chunk.latin1Slice(this._lastPos, i);
+              this._val += ' ';
+              this._lastPos = i + 1;
+              break;
+            case 37: // '%'
+              if (this._encode === 0)
+                this._encode = 1;
+              if (this._lastPos < i)
+                this._val += chunk.latin1Slice(this._lastPos, i);
+              this._lastPos = i + 1;
+              this._byte = -1;
+              i = readPctEnc(this, chunk, i + 1, len);
+              if (i === -1)
+                return cb(new Error('Malformed urlencoded form'));
+              if (i >= len)
+                return cb();
+              ++this._bytesVal;
+              i = skipValBytes(this, chunk, i, len);
+              continue;
+          }
+          ++i;
+          ++this._bytesVal;
+          i = skipValBytes(this, chunk, i, len);
+        }
+        if (this._lastPos < i)
+          this._val += chunk.latin1Slice(this._lastPos, i);
+      }
+    }
+
+    cb();
+  }
+
+  _final(cb) {
+    if (this._byte !== -2)
+      return cb(new Error('Malformed urlencoded form'));
+    if (!this._inKey || this._bytesKey > 0 || this._bytesVal > 0) {
+      if (this._inKey)
+        this._key = this._decoder(this._key, this._encode);
+      else
+        this._val = this._decoder(this._val, this._encode);
+      this.emit(
+        'field',
+        this._key,
+        this._val,
+        { nameTruncated: this._keyTrunc,
+          valueTruncated: this._valTrunc,
+          encoding: this.charset,
+          mimeType: 'text/plain' }
+      );
+    }
+    cb();
+  }
+}
+
+function readPctEnc(self, chunk, pos, len) {
+  if (pos >= len)
+    return len;
+
+  if (self._byte === -1) {
+    // We saw a '%' but no hex characters yet
+    const hexUpper = HEX_VALUES[chunk[pos++]];
+    if (hexUpper === -1)
+      return -1;
+
+    if (hexUpper >= 8)
+      self._encode = 2; // Indicate high bits detected
+
+    if (pos < len) {
+      // Both hex characters are in this chunk
+      const hexLower = HEX_VALUES[chunk[pos++]];
+      if (hexLower === -1)
+        return -1;
+
+      if (self._inKey)
+        self._key += String.fromCharCode((hexUpper << 4) + hexLower);
+      else
+        self._val += String.fromCharCode((hexUpper << 4) + hexLower);
+
+      self._byte = -2;
+      self._lastPos = pos;
+    } else {
+      // Only one hex character was available in this chunk
+      self._byte = hexUpper;
+    }
+  } else {
+    // We saw only one hex character so far
+    const hexLower = HEX_VALUES[chunk[pos++]];
+    if (hexLower === -1)
+      return -1;
+
+    if (self._inKey)
+      self._key += String.fromCharCode((self._byte << 4) + hexLower);
+    else
+      self._val += String.fromCharCode((self._byte << 4) + hexLower);
+
+    self._byte = -2;
+    self._lastPos = pos;
+  }
+
+  return pos;
+}
+
+function skipKeyBytes(self, chunk, pos, len) {
+  // Skip bytes if we've truncated
+  if (self._bytesKey > self.fieldNameSizeLimit) {
+    if (!self._keyTrunc) {
+      if (self._lastPos < pos)
+        self._key += chunk.latin1Slice(self._lastPos, pos - 1);
+    }
+    self._keyTrunc = true;
+    for (; pos < len; ++pos) {
+      const code = chunk[pos];
+      if (code === 61/* '=' */ || code === 38/* '&' */)
+        break;
+      ++self._bytesKey;
+    }
+    self._lastPos = pos;
+  }
+
+  return pos;
+}
+
+function skipValBytes(self, chunk, pos, len) {
+  // Skip bytes if we've truncated
+  if (self._bytesVal > self.fieldSizeLimit) {
+    if (!self._valTrunc) {
+      if (self._lastPos < pos)
+        self._val += chunk.latin1Slice(self._lastPos, pos - 1);
+    }
+    self._valTrunc = true;
+    for (; pos < len; ++pos) {
+      if (chunk[pos] === 38/* '&' */)
+        break;
+      ++self._bytesVal;
+    }
+    self._lastPos = pos;
+  }
+
+  return pos;
+}
+
+/* eslint-disable no-multi-spaces */
+const HEX_VALUES = [
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+];
+/* eslint-enable no-multi-spaces */
+
+module.exports = URLEncoded;

+ 596 - 0
node_modules/busboy/lib/utils.js

@@ -0,0 +1,596 @@
+'use strict';
+
+function parseContentType(str) {
+  if (str.length === 0)
+    return;
+
+  const params = Object.create(null);
+  let i = 0;
+
+  // Parse type
+  for (; i < str.length; ++i) {
+    const code = str.charCodeAt(i);
+    if (TOKEN[code] !== 1) {
+      if (code !== 47/* '/' */ || i === 0)
+        return;
+      break;
+    }
+  }
+  // Check for type without subtype
+  if (i === str.length)
+    return;
+
+  const type = str.slice(0, i).toLowerCase();
+
+  // Parse subtype
+  const subtypeStart = ++i;
+  for (; i < str.length; ++i) {
+    const code = str.charCodeAt(i);
+    if (TOKEN[code] !== 1) {
+      // Make sure we have a subtype
+      if (i === subtypeStart)
+        return;
+
+      if (parseContentTypeParams(str, i, params) === undefined)
+        return;
+      break;
+    }
+  }
+  // Make sure we have a subtype
+  if (i === subtypeStart)
+    return;
+
+  const subtype = str.slice(subtypeStart, i).toLowerCase();
+
+  return { type, subtype, params };
+}
+
+function parseContentTypeParams(str, i, params) {
+  while (i < str.length) {
+    // Consume whitespace
+    for (; i < str.length; ++i) {
+      const code = str.charCodeAt(i);
+      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
+        break;
+    }
+
+    // Ended on whitespace
+    if (i === str.length)
+      break;
+
+    // Check for malformed parameter
+    if (str.charCodeAt(i++) !== 59/* ';' */)
+      return;
+
+    // Consume whitespace
+    for (; i < str.length; ++i) {
+      const code = str.charCodeAt(i);
+      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
+        break;
+    }
+
+    // Ended on whitespace (malformed)
+    if (i === str.length)
+      return;
+
+    let name;
+    const nameStart = i;
+    // Parse parameter name
+    for (; i < str.length; ++i) {
+      const code = str.charCodeAt(i);
+      if (TOKEN[code] !== 1) {
+        if (code !== 61/* '=' */)
+          return;
+        break;
+      }
+    }
+
+    // No value (malformed)
+    if (i === str.length)
+      return;
+
+    name = str.slice(nameStart, i);
+    ++i; // Skip over '='
+
+    // No value (malformed)
+    if (i === str.length)
+      return;
+
+    let value = '';
+    let valueStart;
+    if (str.charCodeAt(i) === 34/* '"' */) {
+      valueStart = ++i;
+      let escaping = false;
+      // Parse quoted value
+      for (; i < str.length; ++i) {
+        const code = str.charCodeAt(i);
+        if (code === 92/* '\\' */) {
+          if (escaping) {
+            valueStart = i;
+            escaping = false;
+          } else {
+            value += str.slice(valueStart, i);
+            escaping = true;
+          }
+          continue;
+        }
+        if (code === 34/* '"' */) {
+          if (escaping) {
+            valueStart = i;
+            escaping = false;
+            continue;
+          }
+          value += str.slice(valueStart, i);
+          break;
+        }
+        if (escaping) {
+          valueStart = i - 1;
+          escaping = false;
+        }
+        // Invalid unescaped quoted character (malformed)
+        if (QDTEXT[code] !== 1)
+          return;
+      }
+
+      // No end quote (malformed)
+      if (i === str.length)
+        return;
+
+      ++i; // Skip over double quote
+    } else {
+      valueStart = i;
+      // Parse unquoted value
+      for (; i < str.length; ++i) {
+        const code = str.charCodeAt(i);
+        if (TOKEN[code] !== 1) {
+          // No value (malformed)
+          if (i === valueStart)
+            return;
+          break;
+        }
+      }
+      value = str.slice(valueStart, i);
+    }
+
+    name = name.toLowerCase();
+    if (params[name] === undefined)
+      params[name] = value;
+  }
+
+  return params;
+}
+
+function parseDisposition(str, defDecoder) {
+  if (str.length === 0)
+    return;
+
+  const params = Object.create(null);
+  let i = 0;
+
+  for (; i < str.length; ++i) {
+    const code = str.charCodeAt(i);
+    if (TOKEN[code] !== 1) {
+      if (parseDispositionParams(str, i, params, defDecoder) === undefined)
+        return;
+      break;
+    }
+  }
+
+  const type = str.slice(0, i).toLowerCase();
+
+  return { type, params };
+}
+
+function parseDispositionParams(str, i, params, defDecoder) {
+  while (i < str.length) {
+    // Consume whitespace
+    for (; i < str.length; ++i) {
+      const code = str.charCodeAt(i);
+      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
+        break;
+    }
+
+    // Ended on whitespace
+    if (i === str.length)
+      break;
+
+    // Check for malformed parameter
+    if (str.charCodeAt(i++) !== 59/* ';' */)
+      return;
+
+    // Consume whitespace
+    for (; i < str.length; ++i) {
+      const code = str.charCodeAt(i);
+      if (code !== 32/* ' ' */ && code !== 9/* '\t' */)
+        break;
+    }
+
+    // Ended on whitespace (malformed)
+    if (i === str.length)
+      return;
+
+    let name;
+    const nameStart = i;
+    // Parse parameter name
+    for (; i < str.length; ++i) {
+      const code = str.charCodeAt(i);
+      if (TOKEN[code] !== 1) {
+        if (code === 61/* '=' */)
+          break;
+        return;
+      }
+    }
+
+    // No value (malformed)
+    if (i === str.length)
+      return;
+
+    let value = '';
+    let valueStart;
+    let charset;
+    //~ let lang;
+    name = str.slice(nameStart, i);
+    if (name.charCodeAt(name.length - 1) === 42/* '*' */) {
+      // Extended value
+
+      const charsetStart = ++i;
+      // Parse charset name
+      for (; i < str.length; ++i) {
+        const code = str.charCodeAt(i);
+        if (CHARSET[code] !== 1) {
+          if (code !== 39/* '\'' */)
+            return;
+          break;
+        }
+      }
+
+      // Incomplete charset (malformed)
+      if (i === str.length)
+        return;
+
+      charset = str.slice(charsetStart, i);
+      ++i; // Skip over the '\''
+
+      //~ const langStart = ++i;
+      // Parse language name
+      for (; i < str.length; ++i) {
+        const code = str.charCodeAt(i);
+        if (code === 39/* '\'' */)
+          break;
+      }
+
+      // Incomplete language (malformed)
+      if (i === str.length)
+        return;
+
+      //~ lang = str.slice(langStart, i);
+      ++i; // Skip over the '\''
+
+      // No value (malformed)
+      if (i === str.length)
+        return;
+
+      valueStart = i;
+
+      let encode = 0;
+      // Parse value
+      for (; i < str.length; ++i) {
+        const code = str.charCodeAt(i);
+        if (EXTENDED_VALUE[code] !== 1) {
+          if (code === 37/* '%' */) {
+            let hexUpper;
+            let hexLower;
+            if (i + 2 < str.length
+                && (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1
+                && (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) {
+              const byteVal = (hexUpper << 4) + hexLower;
+              value += str.slice(valueStart, i);
+              value += String.fromCharCode(byteVal);
+              i += 2;
+              valueStart = i + 1;
+              if (byteVal >= 128)
+                encode = 2;
+              else if (encode === 0)
+                encode = 1;
+              continue;
+            }
+            // '%' disallowed in non-percent encoded contexts (malformed)
+            return;
+          }
+          break;
+        }
+      }
+
+      value += str.slice(valueStart, i);
+      value = convertToUTF8(value, charset, encode);
+      if (value === undefined)
+        return;
+    } else {
+      // Non-extended value
+
+      ++i; // Skip over '='
+
+      // No value (malformed)
+      if (i === str.length)
+        return;
+
+      if (str.charCodeAt(i) === 34/* '"' */) {
+        valueStart = ++i;
+        let escaping = false;
+        // Parse quoted value
+        for (; i < str.length; ++i) {
+          const code = str.charCodeAt(i);
+          if (code === 92/* '\\' */) {
+            if (escaping) {
+              valueStart = i;
+              escaping = false;
+            } else {
+              value += str.slice(valueStart, i);
+              escaping = true;
+            }
+            continue;
+          }
+          if (code === 34/* '"' */) {
+            if (escaping) {
+              valueStart = i;
+              escaping = false;
+              continue;
+            }
+            value += str.slice(valueStart, i);
+            break;
+          }
+          if (escaping) {
+            valueStart = i - 1;
+            escaping = false;
+          }
+          // Invalid unescaped quoted character (malformed)
+          if (QDTEXT[code] !== 1)
+            return;
+        }
+
+        // No end quote (malformed)
+        if (i === str.length)
+          return;
+
+        ++i; // Skip over double quote
+      } else {
+        valueStart = i;
+        // Parse unquoted value
+        for (; i < str.length; ++i) {
+          const code = str.charCodeAt(i);
+          if (TOKEN[code] !== 1) {
+            // No value (malformed)
+            if (i === valueStart)
+              return;
+            break;
+          }
+        }
+        value = str.slice(valueStart, i);
+      }
+
+      value = defDecoder(value, 2);
+      if (value === undefined)
+        return;
+    }
+
+    name = name.toLowerCase();
+    if (params[name] === undefined)
+      params[name] = value;
+  }
+
+  return params;
+}
+
+function getDecoder(charset) {
+  let lc;
+  while (true) {
+    switch (charset) {
+      case 'utf-8':
+      case 'utf8':
+        return decoders.utf8;
+      case 'latin1':
+      case 'ascii': // TODO: Make these a separate, strict decoder?
+      case 'us-ascii':
+      case 'iso-8859-1':
+      case 'iso8859-1':
+      case 'iso88591':
+      case 'iso_8859-1':
+      case 'windows-1252':
+      case 'iso_8859-1:1987':
+      case 'cp1252':
+      case 'x-cp1252':
+        return decoders.latin1;
+      case 'utf16le':
+      case 'utf-16le':
+      case 'ucs2':
+      case 'ucs-2':
+        return decoders.utf16le;
+      case 'base64':
+        return decoders.base64;
+      default:
+        if (lc === undefined) {
+          lc = true;
+          charset = charset.toLowerCase();
+          continue;
+        }
+        return decoders.other.bind(charset);
+    }
+  }
+}
+
+const decoders = {
+  utf8: (data, hint) => {
+    if (data.length === 0)
+      return '';
+    if (typeof data === 'string') {
+      // If `data` never had any percent-encoded bytes or never had any that
+      // were outside of the ASCII range, then we can safely just return the
+      // input since UTF-8 is ASCII compatible
+      if (hint < 2)
+        return data;
+
+      data = Buffer.from(data, 'latin1');
+    }
+    return data.utf8Slice(0, data.length);
+  },
+
+  latin1: (data, hint) => {
+    if (data.length === 0)
+      return '';
+    if (typeof data === 'string')
+      return data;
+    return data.latin1Slice(0, data.length);
+  },
+
+  utf16le: (data, hint) => {
+    if (data.length === 0)
+      return '';
+    if (typeof data === 'string')
+      data = Buffer.from(data, 'latin1');
+    return data.ucs2Slice(0, data.length);
+  },
+
+  base64: (data, hint) => {
+    if (data.length === 0)
+      return '';
+    if (typeof data === 'string')
+      data = Buffer.from(data, 'latin1');
+    return data.base64Slice(0, data.length);
+  },
+
+  other: (data, hint) => {
+    if (data.length === 0)
+      return '';
+    if (typeof data === 'string')
+      data = Buffer.from(data, 'latin1');
+    try {
+      const decoder = new TextDecoder(this);
+      return decoder.decode(data);
+    } catch {}
+  },
+};
+
+function convertToUTF8(data, charset, hint) {
+  const decode = getDecoder(charset);
+  if (decode)
+    return decode(data, hint);
+}
+
+function basename(path) {
+  if (typeof path !== 'string')
+    return '';
+  for (let i = path.length - 1; i >= 0; --i) {
+    switch (path.charCodeAt(i)) {
+      case 0x2F: // '/'
+      case 0x5C: // '\'
+        path = path.slice(i + 1);
+        return (path === '..' || path === '.' ? '' : path);
+    }
+  }
+  return (path === '..' || path === '.' ? '' : path);
+}
+
+const TOKEN = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+];
+
+const QDTEXT = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+];
+
+const CHARSET = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+];
+
+const EXTENDED_VALUE = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+];
+
+/* eslint-disable no-multi-spaces */
+const HEX_VALUES = [
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+];
+/* eslint-enable no-multi-spaces */
+
+module.exports = {
+  basename,
+  convertToUTF8,
+  getDecoder,
+  parseContentType,
+  parseDisposition,
+};

+ 22 - 0
node_modules/busboy/package.json

@@ -0,0 +1,22 @@
+{ "name": "busboy",
+  "version": "1.6.0",
+  "author": "Brian White <mscdex@mscdex.net>",
+  "description": "A streaming parser for HTML form data for node.js",
+  "main": "./lib/index.js",
+  "dependencies": {
+    "streamsearch": "^1.1.0"
+  },
+  "devDependencies": {
+    "@mscdex/eslint-config": "^1.1.0",
+    "eslint": "^7.32.0"
+  },
+  "scripts": {
+    "test": "node test/test.js",
+    "lint": "eslint --cache --report-unused-disable-directives --ext=.js .eslintrc.js lib test bench",
+    "lint:fix": "npm run lint -- --fix"
+  },
+  "engines": { "node": ">=10.16.0" },
+  "keywords": [ "uploads", "forms", "multipart", "form-data" ],
+  "licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/busboy/raw/master/LICENSE" } ],
+  "repository": { "type": "git", "url": "http://github.com/mscdex/busboy.git" }
+}

+ 109 - 0
node_modules/busboy/test/common.js

@@ -0,0 +1,109 @@
+'use strict';
+
+const assert = require('assert');
+const { inspect } = require('util');
+
+const mustCallChecks = [];
+
+function noop() {}
+
+function runCallChecks(exitCode) {
+  if (exitCode !== 0) return;
+
+  const failed = mustCallChecks.filter((context) => {
+    if ('minimum' in context) {
+      context.messageSegment = `at least ${context.minimum}`;
+      return context.actual < context.minimum;
+    }
+    context.messageSegment = `exactly ${context.exact}`;
+    return context.actual !== context.exact;
+  });
+
+  failed.forEach((context) => {
+    console.error('Mismatched %s function calls. Expected %s, actual %d.',
+                  context.name,
+                  context.messageSegment,
+                  context.actual);
+    console.error(context.stack.split('\n').slice(2).join('\n'));
+  });
+
+  if (failed.length)
+    process.exit(1);
+}
+
+function mustCall(fn, exact) {
+  return _mustCallInner(fn, exact, 'exact');
+}
+
+function mustCallAtLeast(fn, minimum) {
+  return _mustCallInner(fn, minimum, 'minimum');
+}
+
+function _mustCallInner(fn, criteria = 1, field) {
+  if (process._exiting)
+    throw new Error('Cannot use common.mustCall*() in process exit handler');
+
+  if (typeof fn === 'number') {
+    criteria = fn;
+    fn = noop;
+  } else if (fn === undefined) {
+    fn = noop;
+  }
+
+  if (typeof criteria !== 'number')
+    throw new TypeError(`Invalid ${field} value: ${criteria}`);
+
+  const context = {
+    [field]: criteria,
+    actual: 0,
+    stack: inspect(new Error()),
+    name: fn.name || '<anonymous>'
+  };
+
+  // Add the exit listener only once to avoid listener leak warnings
+  if (mustCallChecks.length === 0)
+    process.on('exit', runCallChecks);
+
+  mustCallChecks.push(context);
+
+  function wrapped(...args) {
+    ++context.actual;
+    return fn.call(this, ...args);
+  }
+  // TODO: remove origFn?
+  wrapped.origFn = fn;
+
+  return wrapped;
+}
+
+function getCallSite(top) {
+  const originalStackFormatter = Error.prepareStackTrace;
+  Error.prepareStackTrace = (err, stack) =>
+    `${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
+  const err = new Error();
+  Error.captureStackTrace(err, top);
+  // With the V8 Error API, the stack is not formatted until it is accessed
+  // eslint-disable-next-line no-unused-expressions
+  err.stack;
+  Error.prepareStackTrace = originalStackFormatter;
+  return err.stack;
+}
+
+function mustNotCall(msg) {
+  const callSite = getCallSite(mustNotCall);
+  return function mustNotCall(...args) {
+    args = args.map(inspect).join(', ');
+    const argsInfo = (args.length > 0
+                      ? `\ncalled with arguments: ${args}`
+                      : '');
+    assert.fail(
+      `${msg || 'function should not have been called'} at ${callSite}`
+        + argsInfo);
+  };
+}
+
+module.exports = {
+  mustCall,
+  mustCallAtLeast,
+  mustNotCall,
+};

+ 94 - 0
node_modules/busboy/test/test-types-multipart-charsets.js

@@ -0,0 +1,94 @@
+'use strict';
+
+const assert = require('assert');
+const { inspect } = require('util');
+
+const { mustCall } = require(`${__dirname}/common.js`);
+
+const busboy = require('..');
+
+const input = Buffer.from([
+  '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+ 'Content-Disposition: form-data; '
+   + 'name="upload_file_0"; filename="テスト.dat"',
+ 'Content-Type: application/octet-stream',
+ '',
+ 'A'.repeat(1023),
+ '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+].join('\r\n'));
+const boundary = '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k';
+const expected = [
+  { type: 'file',
+    name: 'upload_file_0',
+    data: Buffer.from('A'.repeat(1023)),
+    info: {
+      filename: 'テスト.dat',
+      encoding: '7bit',
+      mimeType: 'application/octet-stream',
+    },
+    limited: false,
+  },
+];
+const bb = busboy({
+  defParamCharset: 'utf8',
+  headers: {
+    'content-type': `multipart/form-data; boundary=${boundary}`,
+  }
+});
+const results = [];
+
+bb.on('field', (name, val, info) => {
+  results.push({ type: 'field', name, val, info });
+});
+
+bb.on('file', (name, stream, info) => {
+  const data = [];
+  let nb = 0;
+  const file = {
+    type: 'file',
+    name,
+    data: null,
+    info,
+    limited: false,
+  };
+  results.push(file);
+  stream.on('data', (d) => {
+    data.push(d);
+    nb += d.length;
+  }).on('limit', () => {
+    file.limited = true;
+  }).on('close', () => {
+    file.data = Buffer.concat(data, nb);
+    assert.strictEqual(stream.truncated, file.limited);
+  }).once('error', (err) => {
+    file.err = err.message;
+  });
+});
+
+bb.on('error', (err) => {
+  results.push({ error: err.message });
+});
+
+bb.on('partsLimit', () => {
+  results.push('partsLimit');
+});
+
+bb.on('filesLimit', () => {
+  results.push('filesLimit');
+});
+
+bb.on('fieldsLimit', () => {
+  results.push('fieldsLimit');
+});
+
+bb.on('close', mustCall(() => {
+  assert.deepStrictEqual(
+    results,
+    expected,
+    'Results mismatch.\n'
+      + `Parsed: ${inspect(results)}\n`
+      + `Expected: ${inspect(expected)}`
+  );
+}));
+
+bb.end(input);

+ 102 - 0
node_modules/busboy/test/test-types-multipart-stream-pause.js

@@ -0,0 +1,102 @@
+'use strict';
+
+const assert = require('assert');
+const { randomFillSync } = require('crypto');
+const { inspect } = require('util');
+
+const busboy = require('..');
+
+const { mustCall } = require('./common.js');
+
+const BOUNDARY = 'u2KxIV5yF1y+xUspOQCCZopaVgeV6Jxihv35XQJmuTx8X3sh';
+
+function formDataSection(key, value) {
+  return Buffer.from(
+    `\r\n--${BOUNDARY}`
+      + `\r\nContent-Disposition: form-data; name="${key}"`
+      + `\r\n\r\n${value}`
+  );
+}
+
+function formDataFile(key, filename, contentType) {
+  const buf = Buffer.allocUnsafe(100000);
+  return Buffer.concat([
+    Buffer.from(`\r\n--${BOUNDARY}\r\n`),
+    Buffer.from(`Content-Disposition: form-data; name="${key}"`
+                  + `; filename="${filename}"\r\n`),
+    Buffer.from(`Content-Type: ${contentType}\r\n\r\n`),
+    randomFillSync(buf)
+  ]);
+}
+
+const reqChunks = [
+  Buffer.concat([
+    formDataFile('file', 'file.bin', 'application/octet-stream'),
+    formDataSection('foo', 'foo value'),
+  ]),
+  formDataSection('bar', 'bar value'),
+  Buffer.from(`\r\n--${BOUNDARY}--\r\n`)
+];
+const bb = busboy({
+  headers: {
+    'content-type': `multipart/form-data; boundary=${BOUNDARY}`
+  }
+});
+const expected = [
+  { type: 'file',
+    name: 'file',
+    info: {
+      filename: 'file.bin',
+      encoding: '7bit',
+      mimeType: 'application/octet-stream',
+    },
+  },
+  { type: 'field',
+    name: 'foo',
+    val: 'foo value',
+    info: {
+      nameTruncated: false,
+      valueTruncated: false,
+      encoding: '7bit',
+      mimeType: 'text/plain',
+    },
+  },
+  { type: 'field',
+    name: 'bar',
+    val: 'bar value',
+    info: {
+      nameTruncated: false,
+      valueTruncated: false,
+      encoding: '7bit',
+      mimeType: 'text/plain',
+    },
+  },
+];
+const results = [];
+
+bb.on('field', (name, val, info) => {
+  results.push({ type: 'field', name, val, info });
+});
+
+bb.on('file', (name, stream, info) => {
+  results.push({ type: 'file', name, info });
+  // Simulate a pipe where the destination is pausing (perhaps due to waiting
+  // for file system write to finish)
+  setTimeout(() => {
+    stream.resume();
+  }, 10);
+});
+
+bb.on('close', mustCall(() => {
+  assert.deepStrictEqual(
+    results,
+    expected,
+    'Results mismatch.\n'
+      + `Parsed: ${inspect(results)}\n`
+      + `Expected: ${inspect(expected)}`
+  );
+}));
+
+for (const chunk of reqChunks)
+  bb.write(chunk);
+bb.end();

+ 1053 - 0
node_modules/busboy/test/test-types-multipart.js

@@ -0,0 +1,1053 @@
+'use strict';
+
+const assert = require('assert');
+const { inspect } = require('util');
+
+const busboy = require('..');
+
+const active = new Map();
+
+const tests = [
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'super alpha file',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_1"',
+       '',
+       'super beta file',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'A'.repeat(1023),
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_1"; filename="1k_b.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'B'.repeat(1023),
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'field',
+        name: 'file_name_0',
+        val: 'super alpha file',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      { type: 'field',
+        name: 'file_name_1',
+        val: 'super beta file',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('A'.repeat(1023)),
+        info: {
+          filename: '1k_a.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_1',
+        data: Buffer.from('B'.repeat(1023)),
+        info: {
+          filename: '1k_b.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Fields and files'
+  },
+  { source: [
+      ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+       'Content-Disposition: form-data; name="cont"',
+       '',
+       'some random content',
+       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+       'Content-Disposition: form-data; name="pass"',
+       '',
+       'some random pass',
+       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+       'Content-Disposition: form-data; name=bit',
+       '',
+       '2',
+       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--'
+      ].join('\r\n')
+    ],
+    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+    expected: [
+      { type: 'field',
+        name: 'cont',
+        val: 'some random content',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      { type: 'field',
+        name: 'pass',
+        val: 'some random pass',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      { type: 'field',
+        name: 'bit',
+        val: '2',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+    ],
+    what: 'Fields only'
+  },
+  { source: [
+      ''
+    ],
+    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+    expected: [
+      { error: 'Unexpected end of form' },
+    ],
+    what: 'No fields and no files'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'super alpha file',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    limits: {
+      fileSize: 13,
+      fieldSize: 5
+    },
+    expected: [
+      { type: 'field',
+        name: 'file_name_0',
+        val: 'super',
+        info: {
+          nameTruncated: false,
+          valueTruncated: true,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('ABCDEFGHIJKLM'),
+        info: {
+          filename: '1k_a.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: true,
+      },
+    ],
+    what: 'Fields and files (limits)'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'super alpha file',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    limits: {
+      files: 0
+    },
+    expected: [
+      { type: 'field',
+        name: 'file_name_0',
+        val: 'super alpha file',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      'filesLimit',
+    ],
+    what: 'Fields and files (limits: 0 files)'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'super alpha file',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_1"',
+       '',
+       'super beta file',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'A'.repeat(1023),
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_1"; filename="1k_b.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'B'.repeat(1023),
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'field',
+        name: 'file_name_0',
+        val: 'super alpha file',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      { type: 'field',
+        name: 'file_name_1',
+        val: 'super beta file',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+    ],
+    events: ['field'],
+    what: 'Fields and (ignored) files'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="/tmp/1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_1"; filename="C:\\files\\1k_b.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_2"; filename="relative/1k_c.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: '1k_a.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_1',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: '1k_b.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_2',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: '1k_c.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Files with filenames containing paths'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="/absolute/1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_1"; filename="C:\\absolute\\1k_b.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_2"; filename="relative/1k_c.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    preservePath: true,
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: '/absolute/1k_a.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_1',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: 'C:\\absolute\\1k_b.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_2',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: 'relative/1k_c.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Paths to be preserved through the preservePath option'
+  },
+  { source: [
+      ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+       'Content-Disposition: form-data; name="cont"',
+       'Content-Type: ',
+       '',
+       'some random content',
+       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+       'Content-Disposition: ',
+       '',
+       'some random pass',
+       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--'
+      ].join('\r\n')
+    ],
+    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+    expected: [
+      { type: 'field',
+        name: 'cont',
+        val: 'some random content',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+    ],
+    what: 'Empty content-type and empty content-disposition'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="file"; filename*=utf-8\'\'n%C3%A4me.txt',
+       'Content-Type: application/octet-stream',
+       '',
+       'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--'
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'file',
+        data: Buffer.from('ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+        info: {
+          filename: 'näme.txt',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Unicode filenames'
+  },
+  { source: [
+      ['--asdasdasdasd\r\n',
+       'Content-Type: text/plain\r\n',
+       'Content-Disposition: form-data; name="foo"\r\n',
+       '\r\n',
+       'asd\r\n',
+       '--asdasdasdasd--'
+      ].join(':)')
+    ],
+    boundary: 'asdasdasdasd',
+    expected: [
+      { error: 'Malformed part header' },
+      { error: 'Unexpected end of form' },
+    ],
+    what: 'Stopped mid-header'
+  },
+  { source: [
+      ['------WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+       'Content-Disposition: form-data; name="cont"',
+       'Content-Type: application/json',
+       '',
+       '{}',
+       '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--',
+      ].join('\r\n')
+    ],
+    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+    expected: [
+      { type: 'field',
+        name: 'cont',
+        val: '{}',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'application/json',
+        },
+      },
+    ],
+    what: 'content-type for fields'
+  },
+  { source: [
+      '------WebKitFormBoundaryTB2MiQ36fnSJlrhY--',
+    ],
+    boundary: '----WebKitFormBoundaryTB2MiQ36fnSJlrhY',
+    expected: [],
+    what: 'empty form'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name=upload_file_0; filename="1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       'Content-Transfer-Encoding: binary',
+       '',
+       '',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.alloc(0),
+        info: {
+          filename: '1k_a.dat',
+          encoding: 'binary',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+        err: 'Unexpected end of form',
+      },
+      { error: 'Unexpected end of form' },
+    ],
+    what: 'Stopped mid-file #1'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name=upload_file_0; filename="1k_a.dat"',
+       'Content-Type: application/octet-stream',
+       '',
+       'a',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('a'),
+        info: {
+          filename: '1k_a.dat',
+          encoding: '7bit',
+          mimeType: 'application/octet-stream',
+        },
+        limited: false,
+        err: 'Unexpected end of form',
+      },
+      { error: 'Unexpected end of form' },
+    ],
+    what: 'Stopped mid-file #2'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="notes.txt"',
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'a',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('a'),
+        info: {
+          filename: 'notes.txt',
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Text file with charset'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="notes.txt"',
+       'Content-Type: ',
+       ' text/plain; charset=utf8',
+       '',
+       'a',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('a'),
+        info: {
+          filename: 'notes.txt',
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Folded header value'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'a',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [],
+    what: 'No Content-Disposition'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'a'.repeat(64 * 1024),
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="notes.txt"',
+       'Content-Type: ',
+       ' text/plain; charset=utf8',
+       '',
+       'bc',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    limits: {
+      fieldSize: Infinity,
+    },
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('bc'),
+        info: {
+          filename: 'notes.txt',
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+    ],
+    events: [ 'file' ],
+    what: 'Skip field parts if no listener'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'a',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="notes.txt"',
+       'Content-Type: ',
+       ' text/plain; charset=utf8',
+       '',
+       'bc',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    limits: {
+      parts: 1,
+    },
+    expected: [
+      { type: 'field',
+        name: 'file_name_0',
+        val: 'a',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      'partsLimit',
+    ],
+    what: 'Parts limit'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_0"',
+       '',
+       'a',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; name="file_name_1"',
+       '',
+       'b',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    limits: {
+      fields: 1,
+    },
+    expected: [
+      { type: 'field',
+        name: 'file_name_0',
+        val: 'a',
+        info: {
+          nameTruncated: false,
+          valueTruncated: false,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+      },
+      'fieldsLimit',
+    ],
+    what: 'Fields limit'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="notes.txt"',
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'ab',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_1"; filename="notes2.txt"',
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'cd',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    limits: {
+      files: 1,
+    },
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('ab'),
+        info: {
+          filename: 'notes.txt',
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+      'filesLimit',
+    ],
+    what: 'Files limit'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + `name="upload_file_0"; filename="${'a'.repeat(64 * 1024)}.txt"`,
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'ab',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_1"; filename="notes2.txt"',
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'cd',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { error: 'Malformed part header' },
+      { type: 'file',
+        name: 'upload_file_1',
+        data: Buffer.from('cd'),
+        info: {
+          filename: 'notes2.txt',
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Oversized part header'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + 'name="upload_file_0"; filename="notes.txt"',
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'a'.repeat(31) + '\r',
+      ].join('\r\n'),
+      'b'.repeat(40),
+      '\r\n-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    fileHwm: 32,
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('a'.repeat(31) + '\r' + 'b'.repeat(40)),
+        info: {
+          filename: 'notes.txt',
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Lookbehind data should not stall file streams'
+  },
+  { source: [
+      ['-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + `name="upload_file_0"; filename="${'a'.repeat(8 * 1024)}.txt"`,
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'ab',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + `name="upload_file_1"; filename="${'b'.repeat(8 * 1024)}.txt"`,
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'cd',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+       'Content-Disposition: form-data; '
+         + `name="upload_file_2"; filename="${'c'.repeat(8 * 1024)}.txt"`,
+       'Content-Type: text/plain; charset=utf8',
+       '',
+       'ef',
+       '-----------------------------paZqsnEHRufoShdX6fh0lUhXBP4k--',
+      ].join('\r\n')
+    ],
+    boundary: '---------------------------paZqsnEHRufoShdX6fh0lUhXBP4k',
+    expected: [
+      { type: 'file',
+        name: 'upload_file_0',
+        data: Buffer.from('ab'),
+        info: {
+          filename: `${'a'.repeat(8 * 1024)}.txt`,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_1',
+        data: Buffer.from('cd'),
+        info: {
+          filename: `${'b'.repeat(8 * 1024)}.txt`,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+      { type: 'file',
+        name: 'upload_file_2',
+        data: Buffer.from('ef'),
+        info: {
+          filename: `${'c'.repeat(8 * 1024)}.txt`,
+          encoding: '7bit',
+          mimeType: 'text/plain',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Header size limit should be per part'
+  },
+  { source: [
+      '\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee\r\n',
+      'Content-Type: application/gzip\r\n'
+        + 'Content-Encoding: gzip\r\n'
+        + 'Content-Disposition: form-data; name=batch-1; filename=batch-1'
+        + '\r\n\r\n',
+      '\r\n--d1bf46b3-aa33-4061-b28d-6c5ced8b08ee--',
+    ],
+    boundary: 'd1bf46b3-aa33-4061-b28d-6c5ced8b08ee',
+    expected: [
+      { type: 'file',
+        name: 'batch-1',
+        data: Buffer.alloc(0),
+        info: {
+          filename: 'batch-1',
+          encoding: '7bit',
+          mimeType: 'application/gzip',
+        },
+        limited: false,
+      },
+    ],
+    what: 'Empty part'
+  },
+];
+
+for (const test of tests) {
+  active.set(test, 1);
+
+  const { what, boundary, events, limits, preservePath, fileHwm } = test;
+  const bb = busboy({
+    fileHwm,
+    limits,
+    preservePath,
+    headers: {
+      'content-type': `multipart/form-data; boundary=${boundary}`,
+    }
+  });
+  const results = [];
+
+  if (events === undefined || events.includes('field')) {
+    bb.on('field', (name, val, info) => {
+      results.push({ type: 'field', name, val, info });
+    });
+  }
+
+  if (events === undefined || events.includes('file')) {
+    bb.on('file', (name, stream, info) => {
+      const data = [];
+      let nb = 0;
+      const file = {
+        type: 'file',
+        name,
+        data: null,
+        info,
+        limited: false,
+      };
+      results.push(file);
+      stream.on('data', (d) => {
+        data.push(d);
+        nb += d.length;
+      }).on('limit', () => {
+        file.limited = true;
+      }).on('close', () => {
+        file.data = Buffer.concat(data, nb);
+        assert.strictEqual(stream.truncated, file.limited);
+      }).once('error', (err) => {
+        file.err = err.message;
+      });
+    });
+  }
+
+  bb.on('error', (err) => {
+    results.push({ error: err.message });
+  });
+
+  bb.on('partsLimit', () => {
+    results.push('partsLimit');
+  });
+
+  bb.on('filesLimit', () => {
+    results.push('filesLimit');
+  });
+
+  bb.on('fieldsLimit', () => {
+    results.push('fieldsLimit');
+  });
+
+  bb.on('close', () => {
+    active.delete(test);
+
+    assert.deepStrictEqual(
+      results,
+      test.expected,
+      `[${what}] Results mismatch.\n`
+        + `Parsed: ${inspect(results)}\n`
+        + `Expected: ${inspect(test.expected)}`
+    );
+  });
+
+  for (const src of test.source) {
+    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
+    bb.write(buf);
+  }
+  bb.end();
+}
+
+// Byte-by-byte versions
+for (let test of tests) {
+  test = { ...test };
+  test.what += ' (byte-by-byte)';
+  active.set(test, 1);
+
+  const { what, boundary, events, limits, preservePath, fileHwm } = test;
+  const bb = busboy({
+    fileHwm,
+    limits,
+    preservePath,
+    headers: {
+      'content-type': `multipart/form-data; boundary=${boundary}`,
+    }
+  });
+  const results = [];
+
+  if (events === undefined || events.includes('field')) {
+    bb.on('field', (name, val, info) => {
+      results.push({ type: 'field', name, val, info });
+    });
+  }
+
+  if (events === undefined || events.includes('file')) {
+    bb.on('file', (name, stream, info) => {
+      const data = [];
+      let nb = 0;
+      const file = {
+        type: 'file',
+        name,
+        data: null,
+        info,
+        limited: false,
+      };
+      results.push(file);
+      stream.on('data', (d) => {
+        data.push(d);
+        nb += d.length;
+      }).on('limit', () => {
+        file.limited = true;
+      }).on('close', () => {
+        file.data = Buffer.concat(data, nb);
+        assert.strictEqual(stream.truncated, file.limited);
+      }).once('error', (err) => {
+        file.err = err.message;
+      });
+    });
+  }
+
+  bb.on('error', (err) => {
+    results.push({ error: err.message });
+  });
+
+  bb.on('partsLimit', () => {
+    results.push('partsLimit');
+  });
+
+  bb.on('filesLimit', () => {
+    results.push('filesLimit');
+  });
+
+  bb.on('fieldsLimit', () => {
+    results.push('fieldsLimit');
+  });
+
+  bb.on('close', () => {
+    active.delete(test);
+
+    assert.deepStrictEqual(
+      results,
+      test.expected,
+      `[${what}] Results mismatch.\n`
+        + `Parsed: ${inspect(results)}\n`
+        + `Expected: ${inspect(test.expected)}`
+    );
+  });
+
+  for (const src of test.source) {
+    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
+    for (let i = 0; i < buf.length; ++i)
+      bb.write(buf.slice(i, i + 1));
+  }
+  bb.end();
+}
+
+{
+  let exception = false;
+  process.once('uncaughtException', (ex) => {
+    exception = true;
+    throw ex;
+  });
+  process.on('exit', () => {
+    if (exception || active.size === 0)
+      return;
+    process.exitCode = 1;
+    console.error('==========================');
+    console.error(`${active.size} test(s) did not finish:`);
+    console.error('==========================');
+    console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
+  });
+}

+ 488 - 0
node_modules/busboy/test/test-types-urlencoded.js

@@ -0,0 +1,488 @@
+'use strict';
+
+const assert = require('assert');
+const { transcode } = require('buffer');
+const { inspect } = require('util');
+
+const busboy = require('..');
+
+const active = new Map();
+
+const tests = [
+  { source: ['foo'],
+    expected: [
+      ['foo',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Unassigned value'
+  },
+  { source: ['foo=bar'],
+    expected: [
+      ['foo',
+       'bar',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Assigned value'
+  },
+  { source: ['foo&bar=baz'],
+    expected: [
+      ['foo',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['bar',
+       'baz',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Unassigned and assigned value'
+  },
+  { source: ['foo=bar&baz'],
+    expected: [
+      ['foo',
+       'bar',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['baz',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Assigned and unassigned value'
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['foo',
+       'bar',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['baz',
+       'bla',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Two assigned values'
+  },
+  { source: ['foo&bar'],
+    expected: [
+      ['foo',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['bar',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Two unassigned values'
+  },
+  { source: ['foo&bar&'],
+    expected: [
+      ['foo',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['bar',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Two unassigned values and ampersand'
+  },
+  { source: ['foo+1=bar+baz%2Bquux'],
+    expected: [
+      ['foo 1',
+       'bar baz+quux',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Assigned key and value with (plus) space'
+  },
+  { source: ['foo=bar%20baz%21'],
+    expected: [
+      ['foo',
+       'bar baz!',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Assigned value with encoded bytes'
+  },
+  { source: ['foo%20bar=baz%20bla%21'],
+    expected: [
+      ['foo bar',
+       'baz bla!',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Assigned value with encoded bytes #2'
+  },
+  { source: ['foo=bar%20baz%21&num=1000'],
+    expected: [
+      ['foo',
+       'bar baz!',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['num',
+       '1000',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Two assigned values, one with encoded bytes'
+  },
+  { source: [
+      Array.from(transcode(Buffer.from('foo'), 'utf8', 'utf16le')).map(
+        (n) => `%${n.toString(16).padStart(2, '0')}`
+      ).join(''),
+      '=',
+      Array.from(transcode(Buffer.from('😀!'), 'utf8', 'utf16le')).map(
+        (n) => `%${n.toString(16).padStart(2, '0')}`
+      ).join(''),
+    ],
+    expected: [
+      ['foo',
+       '😀!',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'UTF-16LE',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    charset: 'UTF-16LE',
+    what: 'Encoded value with multi-byte charset'
+  },
+  { source: [
+      'foo=<',
+      Array.from(transcode(Buffer.from('©:^þ'), 'utf8', 'latin1')).map(
+        (n) => `%${n.toString(16).padStart(2, '0')}`
+      ).join(''),
+    ],
+    expected: [
+      ['foo',
+       '<©:^þ',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'ISO-8859-1',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    charset: 'ISO-8859-1',
+    what: 'Encoded value with single-byte, ASCII-compatible, non-UTF8 charset'
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [],
+    what: 'Limits: zero fields',
+    limits: { fields: 0 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['foo',
+       'bar',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: one field',
+    limits: { fields: 1 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['foo',
+       'bar',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['baz',
+       'bla',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: field part lengths match limits',
+    limits: { fieldNameSize: 3, fieldSize: 3 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['fo',
+       'bar',
+       { nameTruncated: true,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['ba',
+       'bla',
+       { nameTruncated: true,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: truncated field name',
+    limits: { fieldNameSize: 2 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['foo',
+       'ba',
+       { nameTruncated: false,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['baz',
+       'bl',
+       { nameTruncated: false,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: truncated field value',
+    limits: { fieldSize: 2 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['fo',
+       'ba',
+       { nameTruncated: true,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['ba',
+       'bl',
+       { nameTruncated: true,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: truncated field name and value',
+    limits: { fieldNameSize: 2, fieldSize: 2 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['fo',
+       '',
+       { nameTruncated: true,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['ba',
+       '',
+       { nameTruncated: true,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: truncated field name and zero value limit',
+    limits: { fieldNameSize: 2, fieldSize: 0 }
+  },
+  { source: ['foo=bar&baz=bla'],
+    expected: [
+      ['',
+       '',
+       { nameTruncated: true,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+      ['',
+       '',
+       { nameTruncated: true,
+         valueTruncated: true,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Limits: truncated zero field name and zero value limit',
+    limits: { fieldNameSize: 0, fieldSize: 0 }
+  },
+  { source: ['&'],
+    expected: [],
+    what: 'Ampersand'
+  },
+  { source: ['&&&&&'],
+    expected: [],
+    what: 'Many ampersands'
+  },
+  { source: ['='],
+    expected: [
+      ['',
+       '',
+       { nameTruncated: false,
+         valueTruncated: false,
+         encoding: 'utf-8',
+         mimeType: 'text/plain' },
+      ],
+    ],
+    what: 'Assigned value, empty name and value'
+  },
+  { source: [''],
+    expected: [],
+    what: 'Nothing'
+  },
+];
+
+for (const test of tests) {
+  active.set(test, 1);
+
+  const { what } = test;
+  const charset = test.charset || 'utf-8';
+  const bb = busboy({
+    limits: test.limits,
+    headers: {
+      'content-type': `application/x-www-form-urlencoded; charset=${charset}`,
+    },
+  });
+  const results = [];
+
+  bb.on('field', (key, val, info) => {
+    results.push([key, val, info]);
+  });
+
+  bb.on('file', () => {
+    throw new Error(`[${what}] Unexpected file`);
+  });
+
+  bb.on('close', () => {
+    active.delete(test);
+
+    assert.deepStrictEqual(
+      results,
+      test.expected,
+      `[${what}] Results mismatch.\n`
+        + `Parsed: ${inspect(results)}\n`
+        + `Expected: ${inspect(test.expected)}`
+    );
+  });
+
+  for (const src of test.source) {
+    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
+    bb.write(buf);
+  }
+  bb.end();
+}
+
+// Byte-by-byte versions
+for (let test of tests) {
+  test = { ...test };
+  test.what += ' (byte-by-byte)';
+  active.set(test, 1);
+
+  const { what } = test;
+  const charset = test.charset || 'utf-8';
+  const bb = busboy({
+    limits: test.limits,
+    headers: {
+      'content-type': `application/x-www-form-urlencoded; charset="${charset}"`,
+    },
+  });
+  const results = [];
+
+  bb.on('field', (key, val, info) => {
+    results.push([key, val, info]);
+  });
+
+  bb.on('file', () => {
+    throw new Error(`[${what}] Unexpected file`);
+  });
+
+  bb.on('close', () => {
+    active.delete(test);
+
+    assert.deepStrictEqual(
+      results,
+      test.expected,
+      `[${what}] Results mismatch.\n`
+        + `Parsed: ${inspect(results)}\n`
+        + `Expected: ${inspect(test.expected)}`
+    );
+  });
+
+  for (const src of test.source) {
+    const buf = (typeof src === 'string' ? Buffer.from(src, 'utf8') : src);
+    for (let i = 0; i < buf.length; ++i)
+      bb.write(buf.slice(i, i + 1));
+  }
+  bb.end();
+}
+
+{
+  let exception = false;
+  process.once('uncaughtException', (ex) => {
+    exception = true;
+    throw ex;
+  });
+  process.on('exit', () => {
+    if (exception || active.size === 0)
+      return;
+    process.exitCode = 1;
+    console.error('==========================');
+    console.error(`${active.size} test(s) did not finish:`);
+    console.error('==========================');
+    console.error(Array.from(active.keys()).map((v) => v.what).join('\n'));
+  });
+}

+ 20 - 0
node_modules/busboy/test/test.js

@@ -0,0 +1,20 @@
+'use strict';
+
+const { spawnSync } = require('child_process');
+const { readdirSync } = require('fs');
+const { join } = require('path');
+
+const files = readdirSync(__dirname).sort();
+for (const filename of files) {
+  if (filename.startsWith('test-')) {
+    const path = join(__dirname, filename);
+    console.log(`> Running ${filename} ...`);
+    const result = spawnSync(`${process.argv0} ${path}`, {
+      shell: true,
+      stdio: 'inherit',
+      windowsHide: true
+    });
+    if (result.status !== 0)
+      process.exitCode = 1;
+  }
+}

+ 24 - 0
node_modules/concat-stream/LICENSE

@@ -0,0 +1,24 @@
+The MIT License
+
+Copyright (c) 2013 Max Ogden
+
+Permission is hereby granted, free of charge, 
+to any person obtaining a copy of this software and 
+associated documentation files (the "Software"), to 
+deal in the Software without restriction, including 
+without limitation the rights to use, copy, modify, 
+merge, publish, distribute, sublicense, and/or sell 
+copies of the Software, and to permit persons to whom 
+the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice 
+shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 144 - 0
node_modules/concat-stream/index.js

@@ -0,0 +1,144 @@
+var Writable = require('readable-stream').Writable
+var inherits = require('inherits')
+var bufferFrom = require('buffer-from')
+
+if (typeof Uint8Array === 'undefined') {
+  var U8 = require('typedarray').Uint8Array
+} else {
+  var U8 = Uint8Array
+}
+
+function ConcatStream(opts, cb) {
+  if (!(this instanceof ConcatStream)) return new ConcatStream(opts, cb)
+
+  if (typeof opts === 'function') {
+    cb = opts
+    opts = {}
+  }
+  if (!opts) opts = {}
+
+  var encoding = opts.encoding
+  var shouldInferEncoding = false
+
+  if (!encoding) {
+    shouldInferEncoding = true
+  } else {
+    encoding =  String(encoding).toLowerCase()
+    if (encoding === 'u8' || encoding === 'uint8') {
+      encoding = 'uint8array'
+    }
+  }
+
+  Writable.call(this, { objectMode: true })
+
+  this.encoding = encoding
+  this.shouldInferEncoding = shouldInferEncoding
+
+  if (cb) this.on('finish', function () { cb(this.getBody()) })
+  this.body = []
+}
+
+module.exports = ConcatStream
+inherits(ConcatStream, Writable)
+
+ConcatStream.prototype._write = function(chunk, enc, next) {
+  this.body.push(chunk)
+  next()
+}
+
+ConcatStream.prototype.inferEncoding = function (buff) {
+  var firstBuffer = buff === undefined ? this.body[0] : buff;
+  if (Buffer.isBuffer(firstBuffer)) return 'buffer'
+  if (typeof Uint8Array !== 'undefined' && firstBuffer instanceof Uint8Array) return 'uint8array'
+  if (Array.isArray(firstBuffer)) return 'array'
+  if (typeof firstBuffer === 'string') return 'string'
+  if (Object.prototype.toString.call(firstBuffer) === "[object Object]") return 'object'
+  return 'buffer'
+}
+
+ConcatStream.prototype.getBody = function () {
+  if (!this.encoding && this.body.length === 0) return []
+  if (this.shouldInferEncoding) this.encoding = this.inferEncoding()
+  if (this.encoding === 'array') return arrayConcat(this.body)
+  if (this.encoding === 'string') return stringConcat(this.body)
+  if (this.encoding === 'buffer') return bufferConcat(this.body)
+  if (this.encoding === 'uint8array') return u8Concat(this.body)
+  return this.body
+}
+
+var isArray = Array.isArray || function (arr) {
+  return Object.prototype.toString.call(arr) == '[object Array]'
+}
+
+function isArrayish (arr) {
+  return /Array\]$/.test(Object.prototype.toString.call(arr))
+}
+
+function isBufferish (p) {
+  return typeof p === 'string' || isArrayish(p) || (p && typeof p.subarray === 'function')
+}
+
+function stringConcat (parts) {
+  var strings = []
+  var needsToString = false
+  for (var i = 0; i < parts.length; i++) {
+    var p = parts[i]
+    if (typeof p === 'string') {
+      strings.push(p)
+    } else if (Buffer.isBuffer(p)) {
+      strings.push(p)
+    } else if (isBufferish(p)) {
+      strings.push(bufferFrom(p))
+    } else {
+      strings.push(bufferFrom(String(p)))
+    }
+  }
+  if (Buffer.isBuffer(parts[0])) {
+    strings = Buffer.concat(strings)
+    strings = strings.toString('utf8')
+  } else {
+    strings = strings.join('')
+  }
+  return strings
+}
+
+function bufferConcat (parts) {
+  var bufs = []
+  for (var i = 0; i < parts.length; i++) {
+    var p = parts[i]
+    if (Buffer.isBuffer(p)) {
+      bufs.push(p)
+    } else if (isBufferish(p)) {
+      bufs.push(bufferFrom(p))
+    } else {
+      bufs.push(bufferFrom(String(p)))
+    }
+  }
+  return Buffer.concat(bufs)
+}
+
+function arrayConcat (parts) {
+  var res = []
+  for (var i = 0; i < parts.length; i++) {
+    res.push.apply(res, parts[i])
+  }
+  return res
+}
+
+function u8Concat (parts) {
+  var len = 0
+  for (var i = 0; i < parts.length; i++) {
+    if (typeof parts[i] === 'string') {
+      parts[i] = bufferFrom(parts[i])
+    }
+    len += parts[i].length
+  }
+  var u8 = new U8(len)
+  for (var i = 0, offset = 0; i < parts.length; i++) {
+    var part = parts[i]
+    for (var j = 0; j < part.length; j++) {
+      u8[offset++] = part[j]
+    }
+  }
+  return u8
+}

+ 55 - 0
node_modules/concat-stream/package.json

@@ -0,0 +1,55 @@
+{
+  "name": "concat-stream",
+  "version": "1.6.2",
+  "description": "writable stream that concatenates strings or binary data and calls a callback with the result",
+  "tags": [
+    "stream",
+    "simple",
+    "util",
+    "utility"
+  ],
+  "author": "Max Ogden <max@maxogden.com>",
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/maxogden/concat-stream.git"
+  },
+  "bugs": {
+    "url": "http://github.com/maxogden/concat-stream/issues"
+  },
+  "engines": [
+    "node >= 0.8"
+  ],
+  "main": "index.js",
+  "files": [
+    "index.js"
+  ],
+  "scripts": {
+    "test": "tape test/*.js test/server/*.js"
+  },
+  "license": "MIT",
+  "dependencies": {
+    "buffer-from": "^1.0.0",
+    "inherits": "^2.0.3",
+    "readable-stream": "^2.2.2",
+    "typedarray": "^0.0.6"
+  },
+  "devDependencies": {
+    "tape": "^4.6.3"
+  },
+  "testling": {
+    "files": "test/*.js",
+    "browsers": [
+      "ie/8..latest",
+      "firefox/17..latest",
+      "firefox/nightly",
+      "chrome/22..latest",
+      "chrome/canary",
+      "opera/12..latest",
+      "opera/next",
+      "safari/5.1..latest",
+      "ipad/6.0..latest",
+      "iphone/6.0..latest",
+      "android-browser/4.2..latest"
+    ]
+  }
+}

+ 102 - 0
node_modules/concat-stream/readme.md

@@ -0,0 +1,102 @@
+# concat-stream
+
+Writable stream that concatenates all the data from a stream and calls a callback with the result. Use this when you want to collect all the data from a stream into a single buffer.
+
+[![Build Status](https://travis-ci.org/maxogden/concat-stream.svg?branch=master)](https://travis-ci.org/maxogden/concat-stream)
+
+[![NPM](https://nodei.co/npm/concat-stream.png)](https://nodei.co/npm/concat-stream/)
+
+### description
+
+Streams emit many buffers. If you want to collect all of the buffers, and when the stream ends concatenate all of the buffers together and receive a single buffer then this is the module for you.
+
+Only use this if you know you can fit all of the output of your stream into a single Buffer (e.g. in RAM).
+
+There are also `objectMode` streams that emit things other than Buffers, and you can concatenate these too. See below for details.
+
+## Related
+
+`concat-stream` is part of the [mississippi stream utility collection](https://github.com/maxogden/mississippi) which includes more useful stream modules similar to this one.
+
+### examples
+
+#### Buffers
+
+```js
+var fs = require('fs')
+var concat = require('concat-stream')
+
+var readStream = fs.createReadStream('cat.png')
+var concatStream = concat(gotPicture)
+
+readStream.on('error', handleError)
+readStream.pipe(concatStream)
+
+function gotPicture(imageBuffer) {
+  // imageBuffer is all of `cat.png` as a node.js Buffer
+}
+
+function handleError(err) {
+  // handle your error appropriately here, e.g.:
+  console.error(err) // print the error to STDERR
+  process.exit(1) // exit program with non-zero exit code
+}
+
+```
+
+#### Arrays
+
+```js
+var write = concat(function(data) {})
+write.write([1,2,3])
+write.write([4,5,6])
+write.end()
+// data will be [1,2,3,4,5,6] in the above callback
+```
+
+#### Uint8Arrays
+
+```js
+var write = concat(function(data) {})
+var a = new Uint8Array(3)
+a[0] = 97; a[1] = 98; a[2] = 99
+write.write(a)
+write.write('!')
+write.end(Buffer.from('!!1'))
+```
+
+See `test/` for more examples
+
+# methods
+
+```js
+var concat = require('concat-stream')
+```
+
+## var writable = concat(opts={}, cb)
+
+Return a `writable` stream that will fire `cb(data)` with all of the data that
+was written to the stream. Data can be written to `writable` as strings,
+Buffers, arrays of byte integers, and Uint8Arrays. 
+
+By default `concat-stream` will give you back the same data type as the type of the first buffer written to the stream. Use `opts.encoding` to set what format `data` should be returned as, e.g. if you if you don't want to rely on the built-in type checking or for some other reason.
+
+* `string` - get a string
+* `buffer` - get back a Buffer
+* `array` - get an array of byte integers
+* `uint8array`, `u8`, `uint8` - get back a Uint8Array
+* `object`, get back an array of Objects
+
+If you don't specify an encoding, and the types can't be inferred (e.g. you write things that aren't in the list above), it will try to convert concat them into a `Buffer`.
+
+If nothing is written to `writable` then `data` will be an empty array `[]`.
+
+# error handling
+
+`concat-stream` does not handle errors for you, so you must handle errors on whatever streams you pipe into `concat-stream`. This is a general rule when programming with node.js streams: always handle errors on each and every stream. Since `concat-stream` is not itself a stream it does not emit errors.
+
+We recommend using [`end-of-stream`](https://npmjs.org/end-of-stream) or [`pump`](https://npmjs.org/pump) for writing error tolerant stream code.
+
+# license
+
+MIT LICENSE

+ 19 - 0
node_modules/core-util-is/LICENSE

@@ -0,0 +1,19 @@
+Copyright Node.js contributors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.

+ 3 - 0
node_modules/core-util-is/README.md

@@ -0,0 +1,3 @@
+# core-util-is
+
+The `util.is*` functions introduced in Node v0.12.

+ 107 - 0
node_modules/core-util-is/lib/util.js

@@ -0,0 +1,107 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// NOTE: These type checking functions intentionally don't use `instanceof`
+// because it is fragile and can be easily faked with `Object.create()`.
+
+function isArray(arg) {
+  if (Array.isArray) {
+    return Array.isArray(arg);
+  }
+  return objectToString(arg) === '[object Array]';
+}
+exports.isArray = isArray;
+
+function isBoolean(arg) {
+  return typeof arg === 'boolean';
+}
+exports.isBoolean = isBoolean;
+
+function isNull(arg) {
+  return arg === null;
+}
+exports.isNull = isNull;
+
+function isNullOrUndefined(arg) {
+  return arg == null;
+}
+exports.isNullOrUndefined = isNullOrUndefined;
+
+function isNumber(arg) {
+  return typeof arg === 'number';
+}
+exports.isNumber = isNumber;
+
+function isString(arg) {
+  return typeof arg === 'string';
+}
+exports.isString = isString;
+
+function isSymbol(arg) {
+  return typeof arg === 'symbol';
+}
+exports.isSymbol = isSymbol;
+
+function isUndefined(arg) {
+  return arg === void 0;
+}
+exports.isUndefined = isUndefined;
+
+function isRegExp(re) {
+  return objectToString(re) === '[object RegExp]';
+}
+exports.isRegExp = isRegExp;
+
+function isObject(arg) {
+  return typeof arg === 'object' && arg !== null;
+}
+exports.isObject = isObject;
+
+function isDate(d) {
+  return objectToString(d) === '[object Date]';
+}
+exports.isDate = isDate;
+
+function isError(e) {
+  return (objectToString(e) === '[object Error]' || e instanceof Error);
+}
+exports.isError = isError;
+
+function isFunction(arg) {
+  return typeof arg === 'function';
+}
+exports.isFunction = isFunction;
+
+function isPrimitive(arg) {
+  return arg === null ||
+         typeof arg === 'boolean' ||
+         typeof arg === 'number' ||
+         typeof arg === 'string' ||
+         typeof arg === 'symbol' ||  // ES6 symbol
+         typeof arg === 'undefined';
+}
+exports.isPrimitive = isPrimitive;
+
+exports.isBuffer = require('buffer').Buffer.isBuffer;
+
+function objectToString(o) {
+  return Object.prototype.toString.call(o);
+}

+ 38 - 0
node_modules/core-util-is/package.json

@@ -0,0 +1,38 @@
+{
+  "name": "core-util-is",
+  "version": "1.0.3",
+  "description": "The `util.is*` functions introduced in Node v0.12.",
+  "main": "lib/util.js",
+  "files": [
+    "lib"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/isaacs/core-util-is"
+  },
+  "keywords": [
+    "util",
+    "isBuffer",
+    "isArray",
+    "isNumber",
+    "isString",
+    "isRegExp",
+    "isThis",
+    "isThat",
+    "polyfill"
+  ],
+  "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/isaacs/core-util-is/issues"
+  },
+  "scripts": {
+    "test": "tap test.js",
+    "preversion": "npm test",
+    "postversion": "npm publish",
+    "prepublishOnly": "git push origin --follow-tags"
+  },
+  "devDependencies": {
+    "tap": "^15.0.9"
+  }
+}

+ 16 - 0
node_modules/inherits/LICENSE

@@ -0,0 +1,16 @@
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+

+ 42 - 0
node_modules/inherits/README.md

@@ -0,0 +1,42 @@
+Browser-friendly inheritance fully compatible with standard node.js
+[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
+
+This package exports standard `inherits` from node.js `util` module in
+node environment, but also provides alternative browser-friendly
+implementation through [browser
+field](https://gist.github.com/shtylman/4339901). Alternative
+implementation is a literal copy of standard one located in standalone
+module to avoid requiring of `util`. It also has a shim for old
+browsers with no `Object.create` support.
+
+While keeping you sure you are using standard `inherits`
+implementation in node.js environment, it allows bundlers such as
+[browserify](https://github.com/substack/node-browserify) to not
+include full `util` package to your client code if all you need is
+just `inherits` function. It worth, because browser shim for `util`
+package is large and `inherits` is often the single function you need
+from it.
+
+It's recommended to use this package instead of
+`require('util').inherits` for any code that has chances to be used
+not only in node.js but in browser too.
+
+## usage
+
+```js
+var inherits = require('inherits');
+// then use exactly as the standard one
+```
+
+## note on version ~1.0
+
+Version ~1.0 had completely different motivation and is not compatible
+neither with 2.0 nor with standard node.js `inherits`.
+
+If you are using version ~1.0 and planning to switch to ~2.0, be
+careful:
+
+* new version uses `super_` instead of `super` for referencing
+  superclass
+* new version overwrites current prototype while old one preserves any
+  existing fields on it

+ 9 - 0
node_modules/inherits/inherits.js

@@ -0,0 +1,9 @@
+try {
+  var util = require('util');
+  /* istanbul ignore next */
+  if (typeof util.inherits !== 'function') throw '';
+  module.exports = util.inherits;
+} catch (e) {
+  /* istanbul ignore next */
+  module.exports = require('./inherits_browser.js');
+}

+ 27 - 0
node_modules/inherits/inherits_browser.js

@@ -0,0 +1,27 @@
+if (typeof Object.create === 'function') {
+  // implementation from standard node.js 'util' module
+  module.exports = function inherits(ctor, superCtor) {
+    if (superCtor) {
+      ctor.super_ = superCtor
+      ctor.prototype = Object.create(superCtor.prototype, {
+        constructor: {
+          value: ctor,
+          enumerable: false,
+          writable: true,
+          configurable: true
+        }
+      })
+    }
+  };
+} else {
+  // old school shim for old browsers
+  module.exports = function inherits(ctor, superCtor) {
+    if (superCtor) {
+      ctor.super_ = superCtor
+      var TempCtor = function () {}
+      TempCtor.prototype = superCtor.prototype
+      ctor.prototype = new TempCtor()
+      ctor.prototype.constructor = ctor
+    }
+  }
+}

+ 29 - 0
node_modules/inherits/package.json

@@ -0,0 +1,29 @@
+{
+  "name": "inherits",
+  "description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
+  "version": "2.0.4",
+  "keywords": [
+    "inheritance",
+    "class",
+    "klass",
+    "oop",
+    "object-oriented",
+    "inherits",
+    "browser",
+    "browserify"
+  ],
+  "main": "./inherits.js",
+  "browser": "./inherits_browser.js",
+  "repository": "git://github.com/isaacs/inherits",
+  "license": "ISC",
+  "scripts": {
+    "test": "tap"
+  },
+  "devDependencies": {
+    "tap": "^14.2.4"
+  },
+  "files": [
+    "inherits.js",
+    "inherits_browser.js"
+  ]
+}

+ 1 - 0
node_modules/isarray/.npmignore

@@ -0,0 +1 @@
+node_modules

+ 4 - 0
node_modules/isarray/.travis.yml

@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - "0.8"
+  - "0.10"

+ 6 - 0
node_modules/isarray/Makefile

@@ -0,0 +1,6 @@
+
+test:
+	@node_modules/.bin/tape test.js
+
+.PHONY: test
+

+ 60 - 0
node_modules/isarray/README.md

@@ -0,0 +1,60 @@
+
+# isarray
+
+`Array#isArray` for older browsers.
+
+[![build status](https://secure.travis-ci.org/juliangruber/isarray.svg)](http://travis-ci.org/juliangruber/isarray)
+[![downloads](https://img.shields.io/npm/dm/isarray.svg)](https://www.npmjs.org/package/isarray)
+
+[![browser support](https://ci.testling.com/juliangruber/isarray.png)
+](https://ci.testling.com/juliangruber/isarray)
+
+## Usage
+
+```js
+var isArray = require('isarray');
+
+console.log(isArray([])); // => true
+console.log(isArray({})); // => false
+```
+
+## Installation
+
+With [npm](http://npmjs.org) do
+
+```bash
+$ npm install isarray
+```
+
+Then bundle for the browser with
+[browserify](https://github.com/substack/browserify).
+
+With [component](http://component.io) do
+
+```bash
+$ component install juliangruber/isarray
+```
+
+## License
+
+(MIT)
+
+Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 19 - 0
node_modules/isarray/component.json

@@ -0,0 +1,19 @@
+{
+  "name" : "isarray",
+  "description" : "Array#isArray for older browsers",
+  "version" : "0.0.1",
+  "repository" : "juliangruber/isarray",
+  "homepage": "https://github.com/juliangruber/isarray",
+  "main" : "index.js",
+  "scripts" : [
+    "index.js"
+  ],
+  "dependencies" : {},
+  "keywords": ["browser","isarray","array"],
+  "author": {
+    "name": "Julian Gruber",
+    "email": "mail@juliangruber.com",
+    "url": "http://juliangruber.com"
+  },
+  "license": "MIT"
+}

+ 5 - 0
node_modules/isarray/index.js

@@ -0,0 +1,5 @@
+var toString = {}.toString;
+
+module.exports = Array.isArray || function (arr) {
+  return toString.call(arr) == '[object Array]';
+};

+ 45 - 0
node_modules/isarray/package.json

@@ -0,0 +1,45 @@
+{
+  "name": "isarray",
+  "description": "Array#isArray for older browsers",
+  "version": "1.0.0",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/juliangruber/isarray.git"
+  },
+  "homepage": "https://github.com/juliangruber/isarray",
+  "main": "index.js",
+  "dependencies": {},
+  "devDependencies": {
+    "tape": "~2.13.4"
+  },
+  "keywords": [
+    "browser",
+    "isarray",
+    "array"
+  ],
+  "author": {
+    "name": "Julian Gruber",
+    "email": "mail@juliangruber.com",
+    "url": "http://juliangruber.com"
+  },
+  "license": "MIT",
+  "testling": {
+    "files": "test.js",
+    "browsers": [
+      "ie/8..latest",
+      "firefox/17..latest",
+      "firefox/nightly",
+      "chrome/22..latest",
+      "chrome/canary",
+      "opera/12..latest",
+      "opera/next",
+      "safari/5.1..latest",
+      "ipad/6.0..latest",
+      "iphone/6.0..latest",
+      "android-browser/4.2..latest"
+    ]
+  },
+  "scripts": {
+    "test": "tape test.js"
+  }
+}

+ 20 - 0
node_modules/isarray/test.js

@@ -0,0 +1,20 @@
+var isArray = require('./');
+var test = require('tape');
+
+test('is array', function(t){
+  t.ok(isArray([]));
+  t.notOk(isArray({}));
+  t.notOk(isArray(null));
+  t.notOk(isArray(false));
+
+  var obj = {};
+  obj[0] = true;
+  t.notOk(isArray(obj));
+
+  var arr = [];
+  arr.foo = 'bar';
+  t.ok(isArray(arr));
+
+  t.end();
+});
+

+ 22 - 0
node_modules/media-typer/HISTORY.md

@@ -0,0 +1,22 @@
+0.3.0 / 2014-09-07
+==================
+
+  * Support Node.js 0.6
+  * Throw error when parameter format invalid on parse
+
+0.2.0 / 2014-06-18
+==================
+
+  * Add `typer.format()` to format media types
+
+0.1.0 / 2014-06-17
+==================
+
+  * Accept `req` as argument to `parse`
+  * Accept `res` as argument to `parse`
+  * Parse media type with extra LWS between type and first parameter
+
+0.0.0 / 2014-06-13
+==================
+
+  * Initial implementation

+ 22 - 0
node_modules/media-typer/LICENSE

@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2014 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 81 - 0
node_modules/media-typer/README.md

@@ -0,0 +1,81 @@
+# media-typer
+
+[![NPM Version][npm-image]][npm-url]
+[![NPM Downloads][downloads-image]][downloads-url]
+[![Node.js Version][node-version-image]][node-version-url]
+[![Build Status][travis-image]][travis-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+
+Simple RFC 6838 media type parser
+
+## Installation
+
+```sh
+$ npm install media-typer
+```
+
+## API
+
+```js
+var typer = require('media-typer')
+```
+
+### typer.parse(string)
+
+```js
+var obj = typer.parse('image/svg+xml; charset=utf-8')
+```
+
+Parse a media type string. This will return an object with the following
+properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):
+
+ - `type`: The type of the media type (always lower case). Example: `'image'`
+
+ - `subtype`: The subtype of the media type (always lower case). Example: `'svg'`
+
+ - `suffix`: The suffix of the media type (always lower case). Example: `'xml'`
+
+ - `parameters`: An object of the parameters in the media type (name of parameter always lower case). Example: `{charset: 'utf-8'}`
+
+### typer.parse(req)
+
+```js
+var obj = typer.parse(req)
+```
+
+Parse the `content-type` header from the given `req`. Short-cut for
+`typer.parse(req.headers['content-type'])`.
+
+### typer.parse(res)
+
+```js
+var obj = typer.parse(res)
+```
+
+Parse the `content-type` header set on the given `res`. Short-cut for
+`typer.parse(res.getHeader('content-type'))`.
+
+### typer.format(obj)
+
+```js
+var obj = typer.format({type: 'image', subtype: 'svg', suffix: 'xml'})
+```
+
+Format an object into a media type string. This will return a string of the
+mime type for the given object. For the properties of the object, see the
+documentation for `typer.parse(string)`.
+
+## License
+
+[MIT](LICENSE)
+
+[npm-image]: https://img.shields.io/npm/v/media-typer.svg?style=flat
+[npm-url]: https://npmjs.org/package/media-typer
+[node-version-image]: https://img.shields.io/badge/node.js-%3E%3D_0.6-brightgreen.svg?style=flat
+[node-version-url]: http://nodejs.org/download/
+[travis-image]: https://img.shields.io/travis/jshttp/media-typer.svg?style=flat
+[travis-url]: https://travis-ci.org/jshttp/media-typer
+[coveralls-image]: https://img.shields.io/coveralls/jshttp/media-typer.svg?style=flat
+[coveralls-url]: https://coveralls.io/r/jshttp/media-typer
+[downloads-image]: https://img.shields.io/npm/dm/media-typer.svg?style=flat
+[downloads-url]: https://npmjs.org/package/media-typer

+ 270 - 0
node_modules/media-typer/index.js

@@ -0,0 +1,270 @@
+/*!
+ * media-typer
+ * Copyright(c) 2014 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+/**
+ * RegExp to match *( ";" parameter ) in RFC 2616 sec 3.7
+ *
+ * parameter     = token "=" ( token | quoted-string )
+ * token         = 1*<any CHAR except CTLs or separators>
+ * separators    = "(" | ")" | "<" | ">" | "@"
+ *               | "," | ";" | ":" | "\" | <">
+ *               | "/" | "[" | "]" | "?" | "="
+ *               | "{" | "}" | SP | HT
+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ * qdtext        = <any TEXT except <">>
+ * quoted-pair   = "\" CHAR
+ * CHAR          = <any US-ASCII character (octets 0 - 127)>
+ * TEXT          = <any OCTET except CTLs, but including LWS>
+ * LWS           = [CRLF] 1*( SP | HT )
+ * CRLF          = CR LF
+ * CR            = <US-ASCII CR, carriage return (13)>
+ * LF            = <US-ASCII LF, linefeed (10)>
+ * SP            = <US-ASCII SP, space (32)>
+ * SHT           = <US-ASCII HT, horizontal-tab (9)>
+ * CTL           = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
+ * OCTET         = <any 8-bit sequence of data>
+ */
+var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
+var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/
+var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/
+
+/**
+ * RegExp to match quoted-pair in RFC 2616
+ *
+ * quoted-pair = "\" CHAR
+ * CHAR        = <any US-ASCII character (octets 0 - 127)>
+ */
+var qescRegExp = /\\([\u0000-\u007f])/g;
+
+/**
+ * RegExp to match chars that must be quoted-pair in RFC 2616
+ */
+var quoteRegExp = /([\\"])/g;
+
+/**
+ * RegExp to match type in RFC 6838
+ *
+ * type-name = restricted-name
+ * subtype-name = restricted-name
+ * restricted-name = restricted-name-first *126restricted-name-chars
+ * restricted-name-first  = ALPHA / DIGIT
+ * restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
+ *                          "$" / "&" / "-" / "^" / "_"
+ * restricted-name-chars =/ "." ; Characters before first dot always
+ *                              ; specify a facet name
+ * restricted-name-chars =/ "+" ; Characters after last plus always
+ *                              ; specify a structured syntax suffix
+ * ALPHA =  %x41-5A / %x61-7A   ; A-Z / a-z
+ * DIGIT =  %x30-39             ; 0-9
+ */
+var subtypeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/
+var typeNameRegExp = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/
+var typeRegExp = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
+
+/**
+ * Module exports.
+ */
+
+exports.format = format
+exports.parse = parse
+
+/**
+ * Format object to media type.
+ *
+ * @param {object} obj
+ * @return {string}
+ * @api public
+ */
+
+function format(obj) {
+  if (!obj || typeof obj !== 'object') {
+    throw new TypeError('argument obj is required')
+  }
+
+  var parameters = obj.parameters
+  var subtype = obj.subtype
+  var suffix = obj.suffix
+  var type = obj.type
+
+  if (!type || !typeNameRegExp.test(type)) {
+    throw new TypeError('invalid type')
+  }
+
+  if (!subtype || !subtypeNameRegExp.test(subtype)) {
+    throw new TypeError('invalid subtype')
+  }
+
+  // format as type/subtype
+  var string = type + '/' + subtype
+
+  // append +suffix
+  if (suffix) {
+    if (!typeNameRegExp.test(suffix)) {
+      throw new TypeError('invalid suffix')
+    }
+
+    string += '+' + suffix
+  }
+
+  // append parameters
+  if (parameters && typeof parameters === 'object') {
+    var param
+    var params = Object.keys(parameters).sort()
+
+    for (var i = 0; i < params.length; i++) {
+      param = params[i]
+
+      if (!tokenRegExp.test(param)) {
+        throw new TypeError('invalid parameter name')
+      }
+
+      string += '; ' + param + '=' + qstring(parameters[param])
+    }
+  }
+
+  return string
+}
+
+/**
+ * Parse media type to object.
+ *
+ * @param {string|object} string
+ * @return {Object}
+ * @api public
+ */
+
+function parse(string) {
+  if (!string) {
+    throw new TypeError('argument string is required')
+  }
+
+  // support req/res-like objects as argument
+  if (typeof string === 'object') {
+    string = getcontenttype(string)
+  }
+
+  if (typeof string !== 'string') {
+    throw new TypeError('argument string is required to be a string')
+  }
+
+  var index = string.indexOf(';')
+  var type = index !== -1
+    ? string.substr(0, index)
+    : string
+
+  var key
+  var match
+  var obj = splitType(type)
+  var params = {}
+  var value
+
+  paramRegExp.lastIndex = index
+
+  while (match = paramRegExp.exec(string)) {
+    if (match.index !== index) {
+      throw new TypeError('invalid parameter format')
+    }
+
+    index += match[0].length
+    key = match[1].toLowerCase()
+    value = match[2]
+
+    if (value[0] === '"') {
+      // remove quotes and escapes
+      value = value
+        .substr(1, value.length - 2)
+        .replace(qescRegExp, '$1')
+    }
+
+    params[key] = value
+  }
+
+  if (index !== -1 && index !== string.length) {
+    throw new TypeError('invalid parameter format')
+  }
+
+  obj.parameters = params
+
+  return obj
+}
+
+/**
+ * Get content-type from req/res objects.
+ *
+ * @param {object}
+ * @return {Object}
+ * @api private
+ */
+
+function getcontenttype(obj) {
+  if (typeof obj.getHeader === 'function') {
+    // res-like
+    return obj.getHeader('content-type')
+  }
+
+  if (typeof obj.headers === 'object') {
+    // req-like
+    return obj.headers && obj.headers['content-type']
+  }
+}
+
+/**
+ * Quote a string if necessary.
+ *
+ * @param {string} val
+ * @return {string}
+ * @api private
+ */
+
+function qstring(val) {
+  var str = String(val)
+
+  // no need to quote tokens
+  if (tokenRegExp.test(str)) {
+    return str
+  }
+
+  if (str.length > 0 && !textRegExp.test(str)) {
+    throw new TypeError('invalid parameter value')
+  }
+
+  return '"' + str.replace(quoteRegExp, '\\$1') + '"'
+}
+
+/**
+ * Simply "type/subtype+siffx" into parts.
+ *
+ * @param {string} string
+ * @return {Object}
+ * @api private
+ */
+
+function splitType(string) {
+  var match = typeRegExp.exec(string.toLowerCase())
+
+  if (!match) {
+    throw new TypeError('invalid media type')
+  }
+
+  var type = match[1]
+  var subtype = match[2]
+  var suffix
+
+  // suffix after last +
+  var index = subtype.lastIndexOf('+')
+  if (index !== -1) {
+    suffix = subtype.substr(index + 1)
+    subtype = subtype.substr(0, index)
+  }
+
+  var obj = {
+    type: type,
+    subtype: subtype,
+    suffix: suffix
+  }
+
+  return obj
+}

+ 26 - 0
node_modules/media-typer/package.json

@@ -0,0 +1,26 @@
+{
+  "name": "media-typer",
+  "description": "Simple RFC 6838 media type parser and formatter",
+  "version": "0.3.0",
+  "author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
+  "license": "MIT",
+  "repository": "jshttp/media-typer",
+  "devDependencies": {
+    "istanbul": "0.3.2",
+    "mocha": "~1.21.4",
+    "should": "~4.0.4"
+  },
+  "files": [
+    "LICENSE",
+    "HISTORY.md",
+    "index.js"
+  ],
+  "engines": {
+    "node": ">= 0.6"
+  },
+  "scripts": {
+    "test": "mocha --reporter spec --check-leaks --bail test/",
+    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
+    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
+  }
+}

+ 507 - 0
node_modules/mime-db/HISTORY.md

@@ -0,0 +1,507 @@
+1.52.0 / 2022-02-21
+===================
+
+  * Add extensions from IANA for more `image/*` types
+  * Add extension `.asc` to `application/pgp-keys`
+  * Add extensions to various XML types
+  * Add new upstream MIME types
+
+1.51.0 / 2021-11-08
+===================
+
+  * Add new upstream MIME types
+  * Mark `image/vnd.microsoft.icon` as compressible
+  * Mark `image/vnd.ms-dds` as compressible
+
+1.50.0 / 2021-09-15
+===================
+
+  * Add deprecated iWorks mime types and extensions
+  * Add new upstream MIME types
+
+1.49.0 / 2021-07-26
+===================
+
+  * Add extension `.trig` to `application/trig`
+  * Add new upstream MIME types
+
+1.48.0 / 2021-05-30
+===================
+
+  * Add extension `.mvt` to `application/vnd.mapbox-vector-tile`
+  * Add new upstream MIME types
+  * Mark `text/yaml` as compressible
+
+1.47.0 / 2021-04-01
+===================
+
+  * Add new upstream MIME types
+  * Remove ambigious extensions from IANA for `application/*+xml` types
+  * Update primary extension to `.es` for `application/ecmascript`
+
+1.46.0 / 2021-02-13
+===================
+
+  * Add extension `.amr` to `audio/amr`
+  * Add extension `.m4s` to `video/iso.segment`
+  * Add extension `.opus` to `audio/ogg`
+  * Add new upstream MIME types
+
+1.45.0 / 2020-09-22
+===================
+
+  * Add `application/ubjson` with extension `.ubj`
+  * Add `image/avif` with extension `.avif`
+  * Add `image/ktx2` with extension `.ktx2`
+  * Add extension `.dbf` to `application/vnd.dbf`
+  * Add extension `.rar` to `application/vnd.rar`
+  * Add extension `.td` to `application/urc-targetdesc+xml`
+  * Add new upstream MIME types
+  * Fix extension of `application/vnd.apple.keynote` to be `.key`
+
+1.44.0 / 2020-04-22
+===================
+
+  * Add charsets from IANA
+  * Add extension `.cjs` to `application/node`
+  * Add new upstream MIME types
+
+1.43.0 / 2020-01-05
+===================
+
+  * Add `application/x-keepass2` with extension `.kdbx`
+  * Add extension `.mxmf` to `audio/mobile-xmf`
+  * Add extensions from IANA for `application/*+xml` types
+  * Add new upstream MIME types
+
+1.42.0 / 2019-09-25
+===================
+
+  * Add `image/vnd.ms-dds` with extension `.dds`
+  * Add new upstream MIME types
+  * Remove compressible from `multipart/mixed`
+
+1.41.0 / 2019-08-30
+===================
+
+  * Add new upstream MIME types
+  * Add `application/toml` with extension `.toml`
+  * Mark `font/ttf` as compressible
+
+1.40.0 / 2019-04-20
+===================
+
+  * Add extensions from IANA for `model/*` types
+  * Add `text/mdx` with extension `.mdx`
+
+1.39.0 / 2019-04-04
+===================
+
+  * Add extensions `.siv` and `.sieve` to `application/sieve`
+  * Add new upstream MIME types
+
+1.38.0 / 2019-02-04
+===================
+
+  * Add extension `.nq` to `application/n-quads`
+  * Add extension `.nt` to `application/n-triples`
+  * Add new upstream MIME types
+  * Mark `text/less` as compressible
+
+1.37.0 / 2018-10-19
+===================
+
+  * Add extensions to HEIC image types
+  * Add new upstream MIME types
+
+1.36.0 / 2018-08-20
+===================
+
+  * Add Apple file extensions from IANA
+  * Add extensions from IANA for `image/*` types
+  * Add new upstream MIME types
+
+1.35.0 / 2018-07-15
+===================
+
+  * Add extension `.owl` to `application/rdf+xml`
+  * Add new upstream MIME types
+    - Removes extension `.woff` from `application/font-woff`
+
+1.34.0 / 2018-06-03
+===================
+
+  * Add extension `.csl` to `application/vnd.citationstyles.style+xml`
+  * Add extension `.es` to `application/ecmascript`
+  * Add new upstream MIME types
+  * Add `UTF-8` as default charset for `text/turtle`
+  * Mark all XML-derived types as compressible
+
+1.33.0 / 2018-02-15
+===================
+
+  * Add extensions from IANA for `message/*` types
+  * Add new upstream MIME types
+  * Fix some incorrect OOXML types
+  * Remove `application/font-woff2`
+
+1.32.0 / 2017-11-29
+===================
+
+  * Add new upstream MIME types
+  * Update `text/hjson` to registered `application/hjson`
+  * Add `text/shex` with extension `.shex`
+
+1.31.0 / 2017-10-25
+===================
+
+  * Add `application/raml+yaml` with extension `.raml`
+  * Add `application/wasm` with extension `.wasm`
+  * Add new `font` type from IANA
+  * Add new upstream font extensions
+  * Add new upstream MIME types
+  * Add extensions for JPEG-2000 images
+
+1.30.0 / 2017-08-27
+===================
+
+  * Add `application/vnd.ms-outlook`
+  * Add `application/x-arj`
+  * Add extension `.mjs` to `application/javascript`
+  * Add glTF types and extensions
+  * Add new upstream MIME types
+  * Add `text/x-org`
+  * Add VirtualBox MIME types
+  * Fix `source` records for `video/*` types that are IANA
+  * Update `font/opentype` to registered `font/otf`
+
+1.29.0 / 2017-07-10
+===================
+
+  * Add `application/fido.trusted-apps+json`
+  * Add extension `.wadl` to `application/vnd.sun.wadl+xml`
+  * Add new upstream MIME types
+  * Add `UTF-8` as default charset for `text/css`
+
+1.28.0 / 2017-05-14
+===================
+
+  * Add new upstream MIME types
+  * Add extension `.gz` to `application/gzip`
+  * Update extensions `.md` and `.markdown` to be `text/markdown`
+
+1.27.0 / 2017-03-16
+===================
+
+  * Add new upstream MIME types
+  * Add `image/apng` with extension `.apng`
+
+1.26.0 / 2017-01-14
+===================
+
+  * Add new upstream MIME types
+  * Add extension `.geojson` to `application/geo+json`
+
+1.25.0 / 2016-11-11
+===================
+
+  * Add new upstream MIME types
+
+1.24.0 / 2016-09-18
+===================
+
+  * Add `audio/mp3`
+  * Add new upstream MIME types
+
+1.23.0 / 2016-05-01
+===================
+
+  * Add new upstream MIME types
+  * Add extension `.3gpp` to `audio/3gpp`
+
+1.22.0 / 2016-02-15
+===================
+
+  * Add `text/slim`
+  * Add extension `.rng` to `application/xml`
+  * Add new upstream MIME types
+  * Fix extension of `application/dash+xml` to be `.mpd`
+  * Update primary extension to `.m4a` for `audio/mp4`
+
+1.21.0 / 2016-01-06
+===================
+
+  * Add Google document types
+  * Add new upstream MIME types
+
+1.20.0 / 2015-11-10
+===================
+
+  * Add `text/x-suse-ymp`
+  * Add new upstream MIME types
+
+1.19.0 / 2015-09-17
+===================
+
+  * Add `application/vnd.apple.pkpass`
+  * Add new upstream MIME types
+
+1.18.0 / 2015-09-03
+===================
+
+  * Add new upstream MIME types
+
+1.17.0 / 2015-08-13
+===================
+
+  * Add `application/x-msdos-program`
+  * Add `audio/g711-0`
+  * Add `image/vnd.mozilla.apng`
+  * Add extension `.exe` to `application/x-msdos-program`
+
+1.16.0 / 2015-07-29
+===================
+
+  * Add `application/vnd.uri-map`
+
+1.15.0 / 2015-07-13
+===================
+
+  * Add `application/x-httpd-php`
+
+1.14.0 / 2015-06-25
+===================
+
+  * Add `application/scim+json`
+  * Add `application/vnd.3gpp.ussd+xml`
+  * Add `application/vnd.biopax.rdf+xml`
+  * Add `text/x-processing`
+
+1.13.0 / 2015-06-07
+===================
+
+  * Add nginx as a source
+  * Add `application/x-cocoa`
+  * Add `application/x-java-archive-diff`
+  * Add `application/x-makeself`
+  * Add `application/x-perl`
+  * Add `application/x-pilot`
+  * Add `application/x-redhat-package-manager`
+  * Add `application/x-sea`
+  * Add `audio/x-m4a`
+  * Add `audio/x-realaudio`
+  * Add `image/x-jng`
+  * Add `text/mathml`
+
+1.12.0 / 2015-06-05
+===================
+
+  * Add `application/bdoc`
+  * Add `application/vnd.hyperdrive+json`
+  * Add `application/x-bdoc`
+  * Add extension `.rtf` to `text/rtf`
+
+1.11.0 / 2015-05-31
+===================
+
+  * Add `audio/wav`
+  * Add `audio/wave`
+  * Add extension `.litcoffee` to `text/coffeescript`
+  * Add extension `.sfd-hdstx` to `application/vnd.hydrostatix.sof-data`
+  * Add extension `.n-gage` to `application/vnd.nokia.n-gage.symbian.install`
+
+1.10.0 / 2015-05-19
+===================
+
+  * Add `application/vnd.balsamiq.bmpr`
+  * Add `application/vnd.microsoft.portable-executable`
+  * Add `application/x-ns-proxy-autoconfig`
+
+1.9.1 / 2015-04-19
+==================
+
+  * Remove `.json` extension from `application/manifest+json`
+    - This is causing bugs downstream
+
+1.9.0 / 2015-04-19
+==================
+
+  * Add `application/manifest+json`
+  * Add `application/vnd.micro+json`
+  * Add `image/vnd.zbrush.pcx`
+  * Add `image/x-ms-bmp`
+
+1.8.0 / 2015-03-13
+==================
+
+  * Add `application/vnd.citationstyles.style+xml`
+  * Add `application/vnd.fastcopy-disk-image`
+  * Add `application/vnd.gov.sk.xmldatacontainer+xml`
+  * Add extension `.jsonld` to `application/ld+json`
+
+1.7.0 / 2015-02-08
+==================
+
+  * Add `application/vnd.gerber`
+  * Add `application/vnd.msa-disk-image`
+
+1.6.1 / 2015-02-05
+==================
+
+  * Community extensions ownership transferred from `node-mime`
+
+1.6.0 / 2015-01-29
+==================
+
+  * Add `application/jose`
+  * Add `application/jose+json`
+  * Add `application/json-seq`
+  * Add `application/jwk+json`
+  * Add `application/jwk-set+json`
+  * Add `application/jwt`
+  * Add `application/rdap+json`
+  * Add `application/vnd.gov.sk.e-form+xml`
+  * Add `application/vnd.ims.imsccv1p3`
+
+1.5.0 / 2014-12-30
+==================
+
+  * Add `application/vnd.oracle.resource+json`
+  * Fix various invalid MIME type entries
+    - `application/mbox+xml`
+    - `application/oscp-response`
+    - `application/vwg-multiplexed`
+    - `audio/g721`
+
+1.4.0 / 2014-12-21
+==================
+
+  * Add `application/vnd.ims.imsccv1p2`
+  * Fix various invalid MIME type entries
+    - `application/vnd-acucobol`
+    - `application/vnd-curl`
+    - `application/vnd-dart`
+    - `application/vnd-dxr`
+    - `application/vnd-fdf`
+    - `application/vnd-mif`
+    - `application/vnd-sema`
+    - `application/vnd-wap-wmlc`
+    - `application/vnd.adobe.flash-movie`
+    - `application/vnd.dece-zip`
+    - `application/vnd.dvb_service`
+    - `application/vnd.micrografx-igx`
+    - `application/vnd.sealed-doc`
+    - `application/vnd.sealed-eml`
+    - `application/vnd.sealed-mht`
+    - `application/vnd.sealed-ppt`
+    - `application/vnd.sealed-tiff`
+    - `application/vnd.sealed-xls`
+    - `application/vnd.sealedmedia.softseal-html`
+    - `application/vnd.sealedmedia.softseal-pdf`
+    - `application/vnd.wap-slc`
+    - `application/vnd.wap-wbxml`
+    - `audio/vnd.sealedmedia.softseal-mpeg`
+    - `image/vnd-djvu`
+    - `image/vnd-svf`
+    - `image/vnd-wap-wbmp`
+    - `image/vnd.sealed-png`
+    - `image/vnd.sealedmedia.softseal-gif`
+    - `image/vnd.sealedmedia.softseal-jpg`
+    - `model/vnd-dwf`
+    - `model/vnd.parasolid.transmit-binary`
+    - `model/vnd.parasolid.transmit-text`
+    - `text/vnd-a`
+    - `text/vnd-curl`
+    - `text/vnd.wap-wml`
+  * Remove example template MIME types
+    - `application/example`
+    - `audio/example`
+    - `image/example`
+    - `message/example`
+    - `model/example`
+    - `multipart/example`
+    - `text/example`
+    - `video/example`
+
+1.3.1 / 2014-12-16
+==================
+
+  * Fix missing extensions
+    - `application/json5`
+    - `text/hjson`
+
+1.3.0 / 2014-12-07
+==================
+
+  * Add `application/a2l`
+  * Add `application/aml`
+  * Add `application/atfx`
+  * Add `application/atxml`
+  * Add `application/cdfx+xml`
+  * Add `application/dii`
+  * Add `application/json5`
+  * Add `application/lxf`
+  * Add `application/mf4`
+  * Add `application/vnd.apache.thrift.compact`
+  * Add `application/vnd.apache.thrift.json`
+  * Add `application/vnd.coffeescript`
+  * Add `application/vnd.enphase.envoy`
+  * Add `application/vnd.ims.imsccv1p1`
+  * Add `text/csv-schema`
+  * Add `text/hjson`
+  * Add `text/markdown`
+  * Add `text/yaml`
+
+1.2.0 / 2014-11-09
+==================
+
+  * Add `application/cea`
+  * Add `application/dit`
+  * Add `application/vnd.gov.sk.e-form+zip`
+  * Add `application/vnd.tmd.mediaflex.api+xml`
+  * Type `application/epub+zip` is now IANA-registered
+
+1.1.2 / 2014-10-23
+==================
+
+  * Rebuild database for `application/x-www-form-urlencoded` change
+
+1.1.1 / 2014-10-20
+==================
+
+  * Mark `application/x-www-form-urlencoded` as compressible.
+
+1.1.0 / 2014-09-28
+==================
+
+  * Add `application/font-woff2`
+
+1.0.3 / 2014-09-25
+==================
+
+  * Fix engine requirement in package
+
+1.0.2 / 2014-09-25
+==================
+
+  * Add `application/coap-group+json`
+  * Add `application/dcd`
+  * Add `application/vnd.apache.thrift.binary`
+  * Add `image/vnd.tencent.tap`
+  * Mark all JSON-derived types as compressible
+  * Update `text/vtt` data
+
+1.0.1 / 2014-08-30
+==================
+
+  * Fix extension ordering
+
+1.0.0 / 2014-08-30
+==================
+
+  * Add `application/atf`
+  * Add `application/merge-patch+json`
+  * Add `multipart/x-mixed-replace`
+  * Add `source: 'apache'` metadata
+  * Add `source: 'iana'` metadata
+  * Remove badly-assumed charset data

+ 23 - 0
node_modules/mime-db/LICENSE

@@ -0,0 +1,23 @@
+(The MIT License)
+
+Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
+Copyright (c) 2015-2022 Douglas Christopher Wilson <doug@somethingdoug.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 100 - 0
node_modules/mime-db/README.md

@@ -0,0 +1,100 @@
+# mime-db
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Downloads][npm-downloads-image]][npm-url]
+[![Node.js Version][node-image]][node-url]
+[![Build Status][ci-image]][ci-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
+
+This is a large database of mime types and information about them.
+It consists of a single, public JSON file and does not include any logic,
+allowing it to remain as un-opinionated as possible with an API.
+It aggregates data from the following sources:
+
+- http://www.iana.org/assignments/media-types/media-types.xhtml
+- http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
+- http://hg.nginx.org/nginx/raw-file/default/conf/mime.types
+
+## Installation
+
+```bash
+npm install mime-db
+```
+
+### Database Download
+
+If you're crazy enough to use this in the browser, you can just grab the
+JSON file using [jsDelivr](https://www.jsdelivr.com/). It is recommended to
+replace `master` with [a release tag](https://github.com/jshttp/mime-db/tags)
+as the JSON format may change in the future.
+
+```
+https://cdn.jsdelivr.net/gh/jshttp/mime-db@master/db.json
+```
+
+## Usage
+
+```js
+var db = require('mime-db')
+
+// grab data on .js files
+var data = db['application/javascript']
+```
+
+## Data Structure
+
+The JSON file is a map lookup for lowercased mime types.
+Each mime type has the following properties:
+
+- `.source` - where the mime type is defined.
+    If not set, it's probably a custom media type.
+    - `apache` - [Apache common media types](http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types)
+    - `iana` - [IANA-defined media types](http://www.iana.org/assignments/media-types/media-types.xhtml)
+    - `nginx` - [nginx media types](http://hg.nginx.org/nginx/raw-file/default/conf/mime.types)
+- `.extensions[]` - known extensions associated with this mime type.
+- `.compressible` - whether a file of this type can be gzipped.
+- `.charset` - the default charset associated with this type, if any.
+
+If unknown, every property could be `undefined`.
+
+## Contributing
+
+To edit the database, only make PRs against `src/custom-types.json` or
+`src/custom-suffix.json`.
+
+The `src/custom-types.json` file is a JSON object with the MIME type as the
+keys and the values being an object with the following keys:
+
+- `compressible` - leave out if you don't know, otherwise `true`/`false` to
+  indicate whether the data represented by the type is typically compressible.
+- `extensions` - include an array of file extensions that are associated with
+  the type.
+- `notes` - human-readable notes about the type, typically what the type is.
+- `sources` - include an array of URLs of where the MIME type and the associated
+  extensions are sourced from. This needs to be a [primary source](https://en.wikipedia.org/wiki/Primary_source);
+  links to type aggregating sites and Wikipedia are _not acceptable_.
+
+To update the build, run `npm run build`.
+
+### Adding Custom Media Types
+
+The best way to get new media types included in this library is to register
+them with the IANA. The community registration procedure is outlined in
+[RFC 6838 section 5](http://tools.ietf.org/html/rfc6838#section-5). Types
+registered with the IANA are automatically pulled into this library.
+
+If that is not possible / feasible, they can be added directly here as a
+"custom" type. To do this, it is required to have a primary source that
+definitively lists the media type. If an extension is going to be listed as
+associateed with this media type, the source must definitively link the
+media type and extension as well.
+
+[ci-image]: https://badgen.net/github/checks/jshttp/mime-db/master?label=ci
+[ci-url]: https://github.com/jshttp/mime-db/actions?query=workflow%3Aci
+[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-db/master
+[coveralls-url]: https://coveralls.io/r/jshttp/mime-db?branch=master
+[node-image]: https://badgen.net/npm/node/mime-db
+[node-url]: https://nodejs.org/en/download
+[npm-downloads-image]: https://badgen.net/npm/dm/mime-db
+[npm-url]: https://npmjs.org/package/mime-db
+[npm-version-image]: https://badgen.net/npm/v/mime-db

+ 8519 - 0
node_modules/mime-db/db.json

@@ -0,0 +1,8519 @@
+{
+  "application/1d-interleaved-parityfec": {
+    "source": "iana"
+  },
+  "application/3gpdash-qoe-report+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/3gpp-ims+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/3gpphal+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/3gpphalforms+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/a2l": {
+    "source": "iana"
+  },
+  "application/ace+cbor": {
+    "source": "iana"
+  },
+  "application/activemessage": {
+    "source": "iana"
+  },
+  "application/activity+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-costmap+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-costmapfilter+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-directory+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-endpointcost+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-endpointcostparams+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-endpointprop+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-endpointpropparams+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-error+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-networkmap+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-networkmapfilter+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-updatestreamcontrol+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/alto-updatestreamparams+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/aml": {
+    "source": "iana"
+  },
+  "application/andrew-inset": {
+    "source": "iana",
+    "extensions": ["ez"]
+  },
+  "application/applefile": {
+    "source": "iana"
+  },
+  "application/applixware": {
+    "source": "apache",
+    "extensions": ["aw"]
+  },
+  "application/at+jwt": {
+    "source": "iana"
+  },
+  "application/atf": {
+    "source": "iana"
+  },
+  "application/atfx": {
+    "source": "iana"
+  },
+  "application/atom+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["atom"]
+  },
+  "application/atomcat+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["atomcat"]
+  },
+  "application/atomdeleted+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["atomdeleted"]
+  },
+  "application/atomicmail": {
+    "source": "iana"
+  },
+  "application/atomsvc+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["atomsvc"]
+  },
+  "application/atsc-dwd+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["dwd"]
+  },
+  "application/atsc-dynamic-event-message": {
+    "source": "iana"
+  },
+  "application/atsc-held+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["held"]
+  },
+  "application/atsc-rdt+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/atsc-rsat+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rsat"]
+  },
+  "application/atxml": {
+    "source": "iana"
+  },
+  "application/auth-policy+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/bacnet-xdd+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/batch-smtp": {
+    "source": "iana"
+  },
+  "application/bdoc": {
+    "compressible": false,
+    "extensions": ["bdoc"]
+  },
+  "application/beep+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/calendar+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/calendar+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xcs"]
+  },
+  "application/call-completion": {
+    "source": "iana"
+  },
+  "application/cals-1840": {
+    "source": "iana"
+  },
+  "application/captive+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cbor": {
+    "source": "iana"
+  },
+  "application/cbor-seq": {
+    "source": "iana"
+  },
+  "application/cccex": {
+    "source": "iana"
+  },
+  "application/ccmp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/ccxml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ccxml"]
+  },
+  "application/cdfx+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["cdfx"]
+  },
+  "application/cdmi-capability": {
+    "source": "iana",
+    "extensions": ["cdmia"]
+  },
+  "application/cdmi-container": {
+    "source": "iana",
+    "extensions": ["cdmic"]
+  },
+  "application/cdmi-domain": {
+    "source": "iana",
+    "extensions": ["cdmid"]
+  },
+  "application/cdmi-object": {
+    "source": "iana",
+    "extensions": ["cdmio"]
+  },
+  "application/cdmi-queue": {
+    "source": "iana",
+    "extensions": ["cdmiq"]
+  },
+  "application/cdni": {
+    "source": "iana"
+  },
+  "application/cea": {
+    "source": "iana"
+  },
+  "application/cea-2018+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cellml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cfw": {
+    "source": "iana"
+  },
+  "application/city+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/clr": {
+    "source": "iana"
+  },
+  "application/clue+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/clue_info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cms": {
+    "source": "iana"
+  },
+  "application/cnrp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/coap-group+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/coap-payload": {
+    "source": "iana"
+  },
+  "application/commonground": {
+    "source": "iana"
+  },
+  "application/conference-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cose": {
+    "source": "iana"
+  },
+  "application/cose-key": {
+    "source": "iana"
+  },
+  "application/cose-key-set": {
+    "source": "iana"
+  },
+  "application/cpl+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["cpl"]
+  },
+  "application/csrattrs": {
+    "source": "iana"
+  },
+  "application/csta+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cstadata+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/csvm+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/cu-seeme": {
+    "source": "apache",
+    "extensions": ["cu"]
+  },
+  "application/cwt": {
+    "source": "iana"
+  },
+  "application/cybercash": {
+    "source": "iana"
+  },
+  "application/dart": {
+    "compressible": true
+  },
+  "application/dash+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mpd"]
+  },
+  "application/dash-patch+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mpp"]
+  },
+  "application/dashdelta": {
+    "source": "iana"
+  },
+  "application/davmount+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["davmount"]
+  },
+  "application/dca-rft": {
+    "source": "iana"
+  },
+  "application/dcd": {
+    "source": "iana"
+  },
+  "application/dec-dx": {
+    "source": "iana"
+  },
+  "application/dialog-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/dicom": {
+    "source": "iana"
+  },
+  "application/dicom+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/dicom+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/dii": {
+    "source": "iana"
+  },
+  "application/dit": {
+    "source": "iana"
+  },
+  "application/dns": {
+    "source": "iana"
+  },
+  "application/dns+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/dns-message": {
+    "source": "iana"
+  },
+  "application/docbook+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["dbk"]
+  },
+  "application/dots+cbor": {
+    "source": "iana"
+  },
+  "application/dskpp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/dssc+der": {
+    "source": "iana",
+    "extensions": ["dssc"]
+  },
+  "application/dssc+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xdssc"]
+  },
+  "application/dvcs": {
+    "source": "iana"
+  },
+  "application/ecmascript": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["es","ecma"]
+  },
+  "application/edi-consent": {
+    "source": "iana"
+  },
+  "application/edi-x12": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/edifact": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/efi": {
+    "source": "iana"
+  },
+  "application/elm+json": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/elm+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.cap+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/emergencycalldata.comment+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.control+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.deviceinfo+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.ecall.msd": {
+    "source": "iana"
+  },
+  "application/emergencycalldata.providerinfo+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.serviceinfo+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.subscriberinfo+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emergencycalldata.veds+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/emma+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["emma"]
+  },
+  "application/emotionml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["emotionml"]
+  },
+  "application/encaprtp": {
+    "source": "iana"
+  },
+  "application/epp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/epub+zip": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["epub"]
+  },
+  "application/eshop": {
+    "source": "iana"
+  },
+  "application/exi": {
+    "source": "iana",
+    "extensions": ["exi"]
+  },
+  "application/expect-ct-report+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/express": {
+    "source": "iana",
+    "extensions": ["exp"]
+  },
+  "application/fastinfoset": {
+    "source": "iana"
+  },
+  "application/fastsoap": {
+    "source": "iana"
+  },
+  "application/fdt+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["fdt"]
+  },
+  "application/fhir+json": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/fhir+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/fido.trusted-apps+json": {
+    "compressible": true
+  },
+  "application/fits": {
+    "source": "iana"
+  },
+  "application/flexfec": {
+    "source": "iana"
+  },
+  "application/font-sfnt": {
+    "source": "iana"
+  },
+  "application/font-tdpfr": {
+    "source": "iana",
+    "extensions": ["pfr"]
+  },
+  "application/font-woff": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/framework-attributes+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/geo+json": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["geojson"]
+  },
+  "application/geo+json-seq": {
+    "source": "iana"
+  },
+  "application/geopackage+sqlite3": {
+    "source": "iana"
+  },
+  "application/geoxacml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/gltf-buffer": {
+    "source": "iana"
+  },
+  "application/gml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["gml"]
+  },
+  "application/gpx+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["gpx"]
+  },
+  "application/gxf": {
+    "source": "apache",
+    "extensions": ["gxf"]
+  },
+  "application/gzip": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["gz"]
+  },
+  "application/h224": {
+    "source": "iana"
+  },
+  "application/held+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/hjson": {
+    "extensions": ["hjson"]
+  },
+  "application/http": {
+    "source": "iana"
+  },
+  "application/hyperstudio": {
+    "source": "iana",
+    "extensions": ["stk"]
+  },
+  "application/ibe-key-request+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/ibe-pkg-reply+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/ibe-pp-data": {
+    "source": "iana"
+  },
+  "application/iges": {
+    "source": "iana"
+  },
+  "application/im-iscomposing+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/index": {
+    "source": "iana"
+  },
+  "application/index.cmd": {
+    "source": "iana"
+  },
+  "application/index.obj": {
+    "source": "iana"
+  },
+  "application/index.response": {
+    "source": "iana"
+  },
+  "application/index.vnd": {
+    "source": "iana"
+  },
+  "application/inkml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ink","inkml"]
+  },
+  "application/iotp": {
+    "source": "iana"
+  },
+  "application/ipfix": {
+    "source": "iana",
+    "extensions": ["ipfix"]
+  },
+  "application/ipp": {
+    "source": "iana"
+  },
+  "application/isup": {
+    "source": "iana"
+  },
+  "application/its+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["its"]
+  },
+  "application/java-archive": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["jar","war","ear"]
+  },
+  "application/java-serialized-object": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["ser"]
+  },
+  "application/java-vm": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["class"]
+  },
+  "application/javascript": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["js","mjs"]
+  },
+  "application/jf2feed+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/jose": {
+    "source": "iana"
+  },
+  "application/jose+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/jrd+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/jscalendar+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/json": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["json","map"]
+  },
+  "application/json-patch+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/json-seq": {
+    "source": "iana"
+  },
+  "application/json5": {
+    "extensions": ["json5"]
+  },
+  "application/jsonml+json": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["jsonml"]
+  },
+  "application/jwk+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/jwk-set+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/jwt": {
+    "source": "iana"
+  },
+  "application/kpml-request+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/kpml-response+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/ld+json": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["jsonld"]
+  },
+  "application/lgr+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["lgr"]
+  },
+  "application/link-format": {
+    "source": "iana"
+  },
+  "application/load-control+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/lost+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["lostxml"]
+  },
+  "application/lostsync+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/lpf+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/lxf": {
+    "source": "iana"
+  },
+  "application/mac-binhex40": {
+    "source": "iana",
+    "extensions": ["hqx"]
+  },
+  "application/mac-compactpro": {
+    "source": "apache",
+    "extensions": ["cpt"]
+  },
+  "application/macwriteii": {
+    "source": "iana"
+  },
+  "application/mads+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mads"]
+  },
+  "application/manifest+json": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["webmanifest"]
+  },
+  "application/marc": {
+    "source": "iana",
+    "extensions": ["mrc"]
+  },
+  "application/marcxml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mrcx"]
+  },
+  "application/mathematica": {
+    "source": "iana",
+    "extensions": ["ma","nb","mb"]
+  },
+  "application/mathml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mathml"]
+  },
+  "application/mathml-content+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mathml-presentation+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-associated-procedure-description+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-deregister+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-envelope+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-msk+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-msk-response+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-protection-description+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-reception-report+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-register+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-register-response+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-schedule+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbms-user-service-description+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mbox": {
+    "source": "iana",
+    "extensions": ["mbox"]
+  },
+  "application/media-policy-dataset+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mpf"]
+  },
+  "application/media_control+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mediaservercontrol+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mscml"]
+  },
+  "application/merge-patch+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/metalink+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["metalink"]
+  },
+  "application/metalink4+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["meta4"]
+  },
+  "application/mets+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mets"]
+  },
+  "application/mf4": {
+    "source": "iana"
+  },
+  "application/mikey": {
+    "source": "iana"
+  },
+  "application/mipc": {
+    "source": "iana"
+  },
+  "application/missing-blocks+cbor-seq": {
+    "source": "iana"
+  },
+  "application/mmt-aei+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["maei"]
+  },
+  "application/mmt-usd+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["musd"]
+  },
+  "application/mods+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mods"]
+  },
+  "application/moss-keys": {
+    "source": "iana"
+  },
+  "application/moss-signature": {
+    "source": "iana"
+  },
+  "application/mosskey-data": {
+    "source": "iana"
+  },
+  "application/mosskey-request": {
+    "source": "iana"
+  },
+  "application/mp21": {
+    "source": "iana",
+    "extensions": ["m21","mp21"]
+  },
+  "application/mp4": {
+    "source": "iana",
+    "extensions": ["mp4s","m4p"]
+  },
+  "application/mpeg4-generic": {
+    "source": "iana"
+  },
+  "application/mpeg4-iod": {
+    "source": "iana"
+  },
+  "application/mpeg4-iod-xmt": {
+    "source": "iana"
+  },
+  "application/mrb-consumer+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/mrb-publish+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/msc-ivr+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/msc-mixer+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/msword": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["doc","dot"]
+  },
+  "application/mud+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/multipart-core": {
+    "source": "iana"
+  },
+  "application/mxf": {
+    "source": "iana",
+    "extensions": ["mxf"]
+  },
+  "application/n-quads": {
+    "source": "iana",
+    "extensions": ["nq"]
+  },
+  "application/n-triples": {
+    "source": "iana",
+    "extensions": ["nt"]
+  },
+  "application/nasdata": {
+    "source": "iana"
+  },
+  "application/news-checkgroups": {
+    "source": "iana",
+    "charset": "US-ASCII"
+  },
+  "application/news-groupinfo": {
+    "source": "iana",
+    "charset": "US-ASCII"
+  },
+  "application/news-transmission": {
+    "source": "iana"
+  },
+  "application/nlsml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/node": {
+    "source": "iana",
+    "extensions": ["cjs"]
+  },
+  "application/nss": {
+    "source": "iana"
+  },
+  "application/oauth-authz-req+jwt": {
+    "source": "iana"
+  },
+  "application/oblivious-dns-message": {
+    "source": "iana"
+  },
+  "application/ocsp-request": {
+    "source": "iana"
+  },
+  "application/ocsp-response": {
+    "source": "iana"
+  },
+  "application/octet-stream": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]
+  },
+  "application/oda": {
+    "source": "iana",
+    "extensions": ["oda"]
+  },
+  "application/odm+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/odx": {
+    "source": "iana"
+  },
+  "application/oebps-package+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["opf"]
+  },
+  "application/ogg": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["ogx"]
+  },
+  "application/omdoc+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["omdoc"]
+  },
+  "application/onenote": {
+    "source": "apache",
+    "extensions": ["onetoc","onetoc2","onetmp","onepkg"]
+  },
+  "application/opc-nodeset+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/oscore": {
+    "source": "iana"
+  },
+  "application/oxps": {
+    "source": "iana",
+    "extensions": ["oxps"]
+  },
+  "application/p21": {
+    "source": "iana"
+  },
+  "application/p21+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/p2p-overlay+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["relo"]
+  },
+  "application/parityfec": {
+    "source": "iana"
+  },
+  "application/passport": {
+    "source": "iana"
+  },
+  "application/patch-ops-error+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xer"]
+  },
+  "application/pdf": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["pdf"]
+  },
+  "application/pdx": {
+    "source": "iana"
+  },
+  "application/pem-certificate-chain": {
+    "source": "iana"
+  },
+  "application/pgp-encrypted": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["pgp"]
+  },
+  "application/pgp-keys": {
+    "source": "iana",
+    "extensions": ["asc"]
+  },
+  "application/pgp-signature": {
+    "source": "iana",
+    "extensions": ["asc","sig"]
+  },
+  "application/pics-rules": {
+    "source": "apache",
+    "extensions": ["prf"]
+  },
+  "application/pidf+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/pidf-diff+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/pkcs10": {
+    "source": "iana",
+    "extensions": ["p10"]
+  },
+  "application/pkcs12": {
+    "source": "iana"
+  },
+  "application/pkcs7-mime": {
+    "source": "iana",
+    "extensions": ["p7m","p7c"]
+  },
+  "application/pkcs7-signature": {
+    "source": "iana",
+    "extensions": ["p7s"]
+  },
+  "application/pkcs8": {
+    "source": "iana",
+    "extensions": ["p8"]
+  },
+  "application/pkcs8-encrypted": {
+    "source": "iana"
+  },
+  "application/pkix-attr-cert": {
+    "source": "iana",
+    "extensions": ["ac"]
+  },
+  "application/pkix-cert": {
+    "source": "iana",
+    "extensions": ["cer"]
+  },
+  "application/pkix-crl": {
+    "source": "iana",
+    "extensions": ["crl"]
+  },
+  "application/pkix-pkipath": {
+    "source": "iana",
+    "extensions": ["pkipath"]
+  },
+  "application/pkixcmp": {
+    "source": "iana",
+    "extensions": ["pki"]
+  },
+  "application/pls+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["pls"]
+  },
+  "application/poc-settings+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/postscript": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ai","eps","ps"]
+  },
+  "application/ppsp-tracker+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/problem+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/problem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/provenance+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["provx"]
+  },
+  "application/prs.alvestrand.titrax-sheet": {
+    "source": "iana"
+  },
+  "application/prs.cww": {
+    "source": "iana",
+    "extensions": ["cww"]
+  },
+  "application/prs.cyn": {
+    "source": "iana",
+    "charset": "7-BIT"
+  },
+  "application/prs.hpub+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/prs.nprend": {
+    "source": "iana"
+  },
+  "application/prs.plucker": {
+    "source": "iana"
+  },
+  "application/prs.rdf-xml-crypt": {
+    "source": "iana"
+  },
+  "application/prs.xsf+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/pskc+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["pskcxml"]
+  },
+  "application/pvd+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/qsig": {
+    "source": "iana"
+  },
+  "application/raml+yaml": {
+    "compressible": true,
+    "extensions": ["raml"]
+  },
+  "application/raptorfec": {
+    "source": "iana"
+  },
+  "application/rdap+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/rdf+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rdf","owl"]
+  },
+  "application/reginfo+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rif"]
+  },
+  "application/relax-ng-compact-syntax": {
+    "source": "iana",
+    "extensions": ["rnc"]
+  },
+  "application/remote-printing": {
+    "source": "iana"
+  },
+  "application/reputon+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/resource-lists+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rl"]
+  },
+  "application/resource-lists-diff+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rld"]
+  },
+  "application/rfc+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/riscos": {
+    "source": "iana"
+  },
+  "application/rlmi+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/rls-services+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rs"]
+  },
+  "application/route-apd+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rapd"]
+  },
+  "application/route-s-tsid+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["sls"]
+  },
+  "application/route-usd+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rusd"]
+  },
+  "application/rpki-ghostbusters": {
+    "source": "iana",
+    "extensions": ["gbr"]
+  },
+  "application/rpki-manifest": {
+    "source": "iana",
+    "extensions": ["mft"]
+  },
+  "application/rpki-publication": {
+    "source": "iana"
+  },
+  "application/rpki-roa": {
+    "source": "iana",
+    "extensions": ["roa"]
+  },
+  "application/rpki-updown": {
+    "source": "iana"
+  },
+  "application/rsd+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["rsd"]
+  },
+  "application/rss+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["rss"]
+  },
+  "application/rtf": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rtf"]
+  },
+  "application/rtploopback": {
+    "source": "iana"
+  },
+  "application/rtx": {
+    "source": "iana"
+  },
+  "application/samlassertion+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/samlmetadata+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sarif+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sarif-external-properties+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sbe": {
+    "source": "iana"
+  },
+  "application/sbml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["sbml"]
+  },
+  "application/scaip+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/scim+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/scvp-cv-request": {
+    "source": "iana",
+    "extensions": ["scq"]
+  },
+  "application/scvp-cv-response": {
+    "source": "iana",
+    "extensions": ["scs"]
+  },
+  "application/scvp-vp-request": {
+    "source": "iana",
+    "extensions": ["spq"]
+  },
+  "application/scvp-vp-response": {
+    "source": "iana",
+    "extensions": ["spp"]
+  },
+  "application/sdp": {
+    "source": "iana",
+    "extensions": ["sdp"]
+  },
+  "application/secevent+jwt": {
+    "source": "iana"
+  },
+  "application/senml+cbor": {
+    "source": "iana"
+  },
+  "application/senml+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/senml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["senmlx"]
+  },
+  "application/senml-etch+cbor": {
+    "source": "iana"
+  },
+  "application/senml-etch+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/senml-exi": {
+    "source": "iana"
+  },
+  "application/sensml+cbor": {
+    "source": "iana"
+  },
+  "application/sensml+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sensml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["sensmlx"]
+  },
+  "application/sensml-exi": {
+    "source": "iana"
+  },
+  "application/sep+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sep-exi": {
+    "source": "iana"
+  },
+  "application/session-info": {
+    "source": "iana"
+  },
+  "application/set-payment": {
+    "source": "iana"
+  },
+  "application/set-payment-initiation": {
+    "source": "iana",
+    "extensions": ["setpay"]
+  },
+  "application/set-registration": {
+    "source": "iana"
+  },
+  "application/set-registration-initiation": {
+    "source": "iana",
+    "extensions": ["setreg"]
+  },
+  "application/sgml": {
+    "source": "iana"
+  },
+  "application/sgml-open-catalog": {
+    "source": "iana"
+  },
+  "application/shf+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["shf"]
+  },
+  "application/sieve": {
+    "source": "iana",
+    "extensions": ["siv","sieve"]
+  },
+  "application/simple-filter+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/simple-message-summary": {
+    "source": "iana"
+  },
+  "application/simplesymbolcontainer": {
+    "source": "iana"
+  },
+  "application/sipc": {
+    "source": "iana"
+  },
+  "application/slate": {
+    "source": "iana"
+  },
+  "application/smil": {
+    "source": "iana"
+  },
+  "application/smil+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["smi","smil"]
+  },
+  "application/smpte336m": {
+    "source": "iana"
+  },
+  "application/soap+fastinfoset": {
+    "source": "iana"
+  },
+  "application/soap+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sparql-query": {
+    "source": "iana",
+    "extensions": ["rq"]
+  },
+  "application/sparql-results+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["srx"]
+  },
+  "application/spdx+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/spirits-event+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/sql": {
+    "source": "iana"
+  },
+  "application/srgs": {
+    "source": "iana",
+    "extensions": ["gram"]
+  },
+  "application/srgs+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["grxml"]
+  },
+  "application/sru+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["sru"]
+  },
+  "application/ssdl+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["ssdl"]
+  },
+  "application/ssml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ssml"]
+  },
+  "application/stix+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/swid+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["swidtag"]
+  },
+  "application/tamp-apex-update": {
+    "source": "iana"
+  },
+  "application/tamp-apex-update-confirm": {
+    "source": "iana"
+  },
+  "application/tamp-community-update": {
+    "source": "iana"
+  },
+  "application/tamp-community-update-confirm": {
+    "source": "iana"
+  },
+  "application/tamp-error": {
+    "source": "iana"
+  },
+  "application/tamp-sequence-adjust": {
+    "source": "iana"
+  },
+  "application/tamp-sequence-adjust-confirm": {
+    "source": "iana"
+  },
+  "application/tamp-status-query": {
+    "source": "iana"
+  },
+  "application/tamp-status-response": {
+    "source": "iana"
+  },
+  "application/tamp-update": {
+    "source": "iana"
+  },
+  "application/tamp-update-confirm": {
+    "source": "iana"
+  },
+  "application/tar": {
+    "compressible": true
+  },
+  "application/taxii+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/td+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/tei+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["tei","teicorpus"]
+  },
+  "application/tetra_isi": {
+    "source": "iana"
+  },
+  "application/thraud+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["tfi"]
+  },
+  "application/timestamp-query": {
+    "source": "iana"
+  },
+  "application/timestamp-reply": {
+    "source": "iana"
+  },
+  "application/timestamped-data": {
+    "source": "iana",
+    "extensions": ["tsd"]
+  },
+  "application/tlsrpt+gzip": {
+    "source": "iana"
+  },
+  "application/tlsrpt+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/tnauthlist": {
+    "source": "iana"
+  },
+  "application/token-introspection+jwt": {
+    "source": "iana"
+  },
+  "application/toml": {
+    "compressible": true,
+    "extensions": ["toml"]
+  },
+  "application/trickle-ice-sdpfrag": {
+    "source": "iana"
+  },
+  "application/trig": {
+    "source": "iana",
+    "extensions": ["trig"]
+  },
+  "application/ttml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ttml"]
+  },
+  "application/tve-trigger": {
+    "source": "iana"
+  },
+  "application/tzif": {
+    "source": "iana"
+  },
+  "application/tzif-leap": {
+    "source": "iana"
+  },
+  "application/ubjson": {
+    "compressible": false,
+    "extensions": ["ubj"]
+  },
+  "application/ulpfec": {
+    "source": "iana"
+  },
+  "application/urc-grpsheet+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/urc-ressheet+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rsheet"]
+  },
+  "application/urc-targetdesc+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["td"]
+  },
+  "application/urc-uisocketdesc+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vcard+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vcard+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vemmi": {
+    "source": "iana"
+  },
+  "application/vividence.scriptfile": {
+    "source": "apache"
+  },
+  "application/vnd.1000minds.decision-model+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["1km"]
+  },
+  "application/vnd.3gpp-prose+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp-prose-pc3ch+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp-v2x-local-service-information": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.5gnas": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.access-transfer-events+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.bsf+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.gmop+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.gtpc": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.interworking-data": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.lpp": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.mc-signalling-ear": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.mcdata-affiliation-command+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcdata-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcdata-payload": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.mcdata-service-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcdata-signalling": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.mcdata-ue-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcdata-user-profile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-affiliation-command+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-floor-request+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-location-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-mbms-usage-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-service-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-signed+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-ue-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-ue-init-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcptt-user-profile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-affiliation-command+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-affiliation-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-location-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-mbms-usage-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-service-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-transmission-request+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-ue-config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mcvideo-user-profile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.mid-call+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.ngap": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.pfcp": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.pic-bw-large": {
+    "source": "iana",
+    "extensions": ["plb"]
+  },
+  "application/vnd.3gpp.pic-bw-small": {
+    "source": "iana",
+    "extensions": ["psb"]
+  },
+  "application/vnd.3gpp.pic-bw-var": {
+    "source": "iana",
+    "extensions": ["pvb"]
+  },
+  "application/vnd.3gpp.s1ap": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.sms": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp.sms+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.srvcc-ext+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.srvcc-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.state-and-event-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp.ussd+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp2.bcmcsinfo+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.3gpp2.sms": {
+    "source": "iana"
+  },
+  "application/vnd.3gpp2.tcap": {
+    "source": "iana",
+    "extensions": ["tcap"]
+  },
+  "application/vnd.3lightssoftware.imagescal": {
+    "source": "iana"
+  },
+  "application/vnd.3m.post-it-notes": {
+    "source": "iana",
+    "extensions": ["pwn"]
+  },
+  "application/vnd.accpac.simply.aso": {
+    "source": "iana",
+    "extensions": ["aso"]
+  },
+  "application/vnd.accpac.simply.imp": {
+    "source": "iana",
+    "extensions": ["imp"]
+  },
+  "application/vnd.acucobol": {
+    "source": "iana",
+    "extensions": ["acu"]
+  },
+  "application/vnd.acucorp": {
+    "source": "iana",
+    "extensions": ["atc","acutc"]
+  },
+  "application/vnd.adobe.air-application-installer-package+zip": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["air"]
+  },
+  "application/vnd.adobe.flash.movie": {
+    "source": "iana"
+  },
+  "application/vnd.adobe.formscentral.fcdt": {
+    "source": "iana",
+    "extensions": ["fcdt"]
+  },
+  "application/vnd.adobe.fxp": {
+    "source": "iana",
+    "extensions": ["fxp","fxpl"]
+  },
+  "application/vnd.adobe.partial-upload": {
+    "source": "iana"
+  },
+  "application/vnd.adobe.xdp+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xdp"]
+  },
+  "application/vnd.adobe.xfdf": {
+    "source": "iana",
+    "extensions": ["xfdf"]
+  },
+  "application/vnd.aether.imp": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.afplinedata": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.afplinedata-pagedef": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.cmoca-cmresource": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.foca-charset": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.foca-codedfont": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.foca-codepage": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca-cmtable": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca-formdef": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca-mediummap": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca-objectcontainer": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca-overlay": {
+    "source": "iana"
+  },
+  "application/vnd.afpc.modca-pagesegment": {
+    "source": "iana"
+  },
+  "application/vnd.age": {
+    "source": "iana",
+    "extensions": ["age"]
+  },
+  "application/vnd.ah-barcode": {
+    "source": "iana"
+  },
+  "application/vnd.ahead.space": {
+    "source": "iana",
+    "extensions": ["ahead"]
+  },
+  "application/vnd.airzip.filesecure.azf": {
+    "source": "iana",
+    "extensions": ["azf"]
+  },
+  "application/vnd.airzip.filesecure.azs": {
+    "source": "iana",
+    "extensions": ["azs"]
+  },
+  "application/vnd.amadeus+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.amazon.ebook": {
+    "source": "apache",
+    "extensions": ["azw"]
+  },
+  "application/vnd.amazon.mobi8-ebook": {
+    "source": "iana"
+  },
+  "application/vnd.americandynamics.acc": {
+    "source": "iana",
+    "extensions": ["acc"]
+  },
+  "application/vnd.amiga.ami": {
+    "source": "iana",
+    "extensions": ["ami"]
+  },
+  "application/vnd.amundsen.maze+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.android.ota": {
+    "source": "iana"
+  },
+  "application/vnd.android.package-archive": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["apk"]
+  },
+  "application/vnd.anki": {
+    "source": "iana"
+  },
+  "application/vnd.anser-web-certificate-issue-initiation": {
+    "source": "iana",
+    "extensions": ["cii"]
+  },
+  "application/vnd.anser-web-funds-transfer-initiation": {
+    "source": "apache",
+    "extensions": ["fti"]
+  },
+  "application/vnd.antix.game-component": {
+    "source": "iana",
+    "extensions": ["atx"]
+  },
+  "application/vnd.apache.arrow.file": {
+    "source": "iana"
+  },
+  "application/vnd.apache.arrow.stream": {
+    "source": "iana"
+  },
+  "application/vnd.apache.thrift.binary": {
+    "source": "iana"
+  },
+  "application/vnd.apache.thrift.compact": {
+    "source": "iana"
+  },
+  "application/vnd.apache.thrift.json": {
+    "source": "iana"
+  },
+  "application/vnd.api+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.aplextor.warrp+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.apothekende.reservation+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.apple.installer+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mpkg"]
+  },
+  "application/vnd.apple.keynote": {
+    "source": "iana",
+    "extensions": ["key"]
+  },
+  "application/vnd.apple.mpegurl": {
+    "source": "iana",
+    "extensions": ["m3u8"]
+  },
+  "application/vnd.apple.numbers": {
+    "source": "iana",
+    "extensions": ["numbers"]
+  },
+  "application/vnd.apple.pages": {
+    "source": "iana",
+    "extensions": ["pages"]
+  },
+  "application/vnd.apple.pkpass": {
+    "compressible": false,
+    "extensions": ["pkpass"]
+  },
+  "application/vnd.arastra.swi": {
+    "source": "iana"
+  },
+  "application/vnd.aristanetworks.swi": {
+    "source": "iana",
+    "extensions": ["swi"]
+  },
+  "application/vnd.artisan+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.artsquare": {
+    "source": "iana"
+  },
+  "application/vnd.astraea-software.iota": {
+    "source": "iana",
+    "extensions": ["iota"]
+  },
+  "application/vnd.audiograph": {
+    "source": "iana",
+    "extensions": ["aep"]
+  },
+  "application/vnd.autopackage": {
+    "source": "iana"
+  },
+  "application/vnd.avalon+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.avistar+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.balsamiq.bmml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["bmml"]
+  },
+  "application/vnd.balsamiq.bmpr": {
+    "source": "iana"
+  },
+  "application/vnd.banana-accounting": {
+    "source": "iana"
+  },
+  "application/vnd.bbf.usp.error": {
+    "source": "iana"
+  },
+  "application/vnd.bbf.usp.msg": {
+    "source": "iana"
+  },
+  "application/vnd.bbf.usp.msg+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.bekitzur-stech+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.bint.med-content": {
+    "source": "iana"
+  },
+  "application/vnd.biopax.rdf+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.blink-idb-value-wrapper": {
+    "source": "iana"
+  },
+  "application/vnd.blueice.multipass": {
+    "source": "iana",
+    "extensions": ["mpm"]
+  },
+  "application/vnd.bluetooth.ep.oob": {
+    "source": "iana"
+  },
+  "application/vnd.bluetooth.le.oob": {
+    "source": "iana"
+  },
+  "application/vnd.bmi": {
+    "source": "iana",
+    "extensions": ["bmi"]
+  },
+  "application/vnd.bpf": {
+    "source": "iana"
+  },
+  "application/vnd.bpf3": {
+    "source": "iana"
+  },
+  "application/vnd.businessobjects": {
+    "source": "iana",
+    "extensions": ["rep"]
+  },
+  "application/vnd.byu.uapi+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.cab-jscript": {
+    "source": "iana"
+  },
+  "application/vnd.canon-cpdl": {
+    "source": "iana"
+  },
+  "application/vnd.canon-lips": {
+    "source": "iana"
+  },
+  "application/vnd.capasystems-pg+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.cendio.thinlinc.clientconf": {
+    "source": "iana"
+  },
+  "application/vnd.century-systems.tcp_stream": {
+    "source": "iana"
+  },
+  "application/vnd.chemdraw+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["cdxml"]
+  },
+  "application/vnd.chess-pgn": {
+    "source": "iana"
+  },
+  "application/vnd.chipnuts.karaoke-mmd": {
+    "source": "iana",
+    "extensions": ["mmd"]
+  },
+  "application/vnd.ciedi": {
+    "source": "iana"
+  },
+  "application/vnd.cinderella": {
+    "source": "iana",
+    "extensions": ["cdy"]
+  },
+  "application/vnd.cirpack.isdn-ext": {
+    "source": "iana"
+  },
+  "application/vnd.citationstyles.style+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["csl"]
+  },
+  "application/vnd.claymore": {
+    "source": "iana",
+    "extensions": ["cla"]
+  },
+  "application/vnd.cloanto.rp9": {
+    "source": "iana",
+    "extensions": ["rp9"]
+  },
+  "application/vnd.clonk.c4group": {
+    "source": "iana",
+    "extensions": ["c4g","c4d","c4f","c4p","c4u"]
+  },
+  "application/vnd.cluetrust.cartomobile-config": {
+    "source": "iana",
+    "extensions": ["c11amc"]
+  },
+  "application/vnd.cluetrust.cartomobile-config-pkg": {
+    "source": "iana",
+    "extensions": ["c11amz"]
+  },
+  "application/vnd.coffeescript": {
+    "source": "iana"
+  },
+  "application/vnd.collabio.xodocuments.document": {
+    "source": "iana"
+  },
+  "application/vnd.collabio.xodocuments.document-template": {
+    "source": "iana"
+  },
+  "application/vnd.collabio.xodocuments.presentation": {
+    "source": "iana"
+  },
+  "application/vnd.collabio.xodocuments.presentation-template": {
+    "source": "iana"
+  },
+  "application/vnd.collabio.xodocuments.spreadsheet": {
+    "source": "iana"
+  },
+  "application/vnd.collabio.xodocuments.spreadsheet-template": {
+    "source": "iana"
+  },
+  "application/vnd.collection+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.collection.doc+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.collection.next+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.comicbook+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.comicbook-rar": {
+    "source": "iana"
+  },
+  "application/vnd.commerce-battelle": {
+    "source": "iana"
+  },
+  "application/vnd.commonspace": {
+    "source": "iana",
+    "extensions": ["csp"]
+  },
+  "application/vnd.contact.cmsg": {
+    "source": "iana",
+    "extensions": ["cdbcmsg"]
+  },
+  "application/vnd.coreos.ignition+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.cosmocaller": {
+    "source": "iana",
+    "extensions": ["cmc"]
+  },
+  "application/vnd.crick.clicker": {
+    "source": "iana",
+    "extensions": ["clkx"]
+  },
+  "application/vnd.crick.clicker.keyboard": {
+    "source": "iana",
+    "extensions": ["clkk"]
+  },
+  "application/vnd.crick.clicker.palette": {
+    "source": "iana",
+    "extensions": ["clkp"]
+  },
+  "application/vnd.crick.clicker.template": {
+    "source": "iana",
+    "extensions": ["clkt"]
+  },
+  "application/vnd.crick.clicker.wordbank": {
+    "source": "iana",
+    "extensions": ["clkw"]
+  },
+  "application/vnd.criticaltools.wbs+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["wbs"]
+  },
+  "application/vnd.cryptii.pipe+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.crypto-shade-file": {
+    "source": "iana"
+  },
+  "application/vnd.cryptomator.encrypted": {
+    "source": "iana"
+  },
+  "application/vnd.cryptomator.vault": {
+    "source": "iana"
+  },
+  "application/vnd.ctc-posml": {
+    "source": "iana",
+    "extensions": ["pml"]
+  },
+  "application/vnd.ctct.ws+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.cups-pdf": {
+    "source": "iana"
+  },
+  "application/vnd.cups-postscript": {
+    "source": "iana"
+  },
+  "application/vnd.cups-ppd": {
+    "source": "iana",
+    "extensions": ["ppd"]
+  },
+  "application/vnd.cups-raster": {
+    "source": "iana"
+  },
+  "application/vnd.cups-raw": {
+    "source": "iana"
+  },
+  "application/vnd.curl": {
+    "source": "iana"
+  },
+  "application/vnd.curl.car": {
+    "source": "apache",
+    "extensions": ["car"]
+  },
+  "application/vnd.curl.pcurl": {
+    "source": "apache",
+    "extensions": ["pcurl"]
+  },
+  "application/vnd.cyan.dean.root+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.cybank": {
+    "source": "iana"
+  },
+  "application/vnd.cyclonedx+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.cyclonedx+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.d2l.coursepackage1p0+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.d3m-dataset": {
+    "source": "iana"
+  },
+  "application/vnd.d3m-problem": {
+    "source": "iana"
+  },
+  "application/vnd.dart": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["dart"]
+  },
+  "application/vnd.data-vision.rdz": {
+    "source": "iana",
+    "extensions": ["rdz"]
+  },
+  "application/vnd.datapackage+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dataresource+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dbf": {
+    "source": "iana",
+    "extensions": ["dbf"]
+  },
+  "application/vnd.debian.binary-package": {
+    "source": "iana"
+  },
+  "application/vnd.dece.data": {
+    "source": "iana",
+    "extensions": ["uvf","uvvf","uvd","uvvd"]
+  },
+  "application/vnd.dece.ttml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["uvt","uvvt"]
+  },
+  "application/vnd.dece.unspecified": {
+    "source": "iana",
+    "extensions": ["uvx","uvvx"]
+  },
+  "application/vnd.dece.zip": {
+    "source": "iana",
+    "extensions": ["uvz","uvvz"]
+  },
+  "application/vnd.denovo.fcselayout-link": {
+    "source": "iana",
+    "extensions": ["fe_launch"]
+  },
+  "application/vnd.desmume.movie": {
+    "source": "iana"
+  },
+  "application/vnd.dir-bi.plate-dl-nosuffix": {
+    "source": "iana"
+  },
+  "application/vnd.dm.delegation+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dna": {
+    "source": "iana",
+    "extensions": ["dna"]
+  },
+  "application/vnd.document+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dolby.mlp": {
+    "source": "apache",
+    "extensions": ["mlp"]
+  },
+  "application/vnd.dolby.mobile.1": {
+    "source": "iana"
+  },
+  "application/vnd.dolby.mobile.2": {
+    "source": "iana"
+  },
+  "application/vnd.doremir.scorecloud-binary-document": {
+    "source": "iana"
+  },
+  "application/vnd.dpgraph": {
+    "source": "iana",
+    "extensions": ["dpg"]
+  },
+  "application/vnd.dreamfactory": {
+    "source": "iana",
+    "extensions": ["dfac"]
+  },
+  "application/vnd.drive+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ds-keypoint": {
+    "source": "apache",
+    "extensions": ["kpxx"]
+  },
+  "application/vnd.dtg.local": {
+    "source": "iana"
+  },
+  "application/vnd.dtg.local.flash": {
+    "source": "iana"
+  },
+  "application/vnd.dtg.local.html": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.ait": {
+    "source": "iana",
+    "extensions": ["ait"]
+  },
+  "application/vnd.dvb.dvbisl+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.dvbj": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.esgcontainer": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.ipdcdftnotifaccess": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.ipdcesgaccess": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.ipdcesgaccess2": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.ipdcesgpdd": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.ipdcroaming": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.iptv.alfec-base": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.iptv.alfec-enhancement": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.notif-aggregate-root+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.notif-container+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.notif-generic+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.notif-ia-msglist+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.notif-ia-registration-request+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.notif-ia-registration-response+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.notif-init+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.dvb.pfr": {
+    "source": "iana"
+  },
+  "application/vnd.dvb.service": {
+    "source": "iana",
+    "extensions": ["svc"]
+  },
+  "application/vnd.dxr": {
+    "source": "iana"
+  },
+  "application/vnd.dynageo": {
+    "source": "iana",
+    "extensions": ["geo"]
+  },
+  "application/vnd.dzr": {
+    "source": "iana"
+  },
+  "application/vnd.easykaraoke.cdgdownload": {
+    "source": "iana"
+  },
+  "application/vnd.ecdis-update": {
+    "source": "iana"
+  },
+  "application/vnd.ecip.rlp": {
+    "source": "iana"
+  },
+  "application/vnd.eclipse.ditto+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ecowin.chart": {
+    "source": "iana",
+    "extensions": ["mag"]
+  },
+  "application/vnd.ecowin.filerequest": {
+    "source": "iana"
+  },
+  "application/vnd.ecowin.fileupdate": {
+    "source": "iana"
+  },
+  "application/vnd.ecowin.series": {
+    "source": "iana"
+  },
+  "application/vnd.ecowin.seriesrequest": {
+    "source": "iana"
+  },
+  "application/vnd.ecowin.seriesupdate": {
+    "source": "iana"
+  },
+  "application/vnd.efi.img": {
+    "source": "iana"
+  },
+  "application/vnd.efi.iso": {
+    "source": "iana"
+  },
+  "application/vnd.emclient.accessrequest+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.enliven": {
+    "source": "iana",
+    "extensions": ["nml"]
+  },
+  "application/vnd.enphase.envoy": {
+    "source": "iana"
+  },
+  "application/vnd.eprints.data+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.epson.esf": {
+    "source": "iana",
+    "extensions": ["esf"]
+  },
+  "application/vnd.epson.msf": {
+    "source": "iana",
+    "extensions": ["msf"]
+  },
+  "application/vnd.epson.quickanime": {
+    "source": "iana",
+    "extensions": ["qam"]
+  },
+  "application/vnd.epson.salt": {
+    "source": "iana",
+    "extensions": ["slt"]
+  },
+  "application/vnd.epson.ssf": {
+    "source": "iana",
+    "extensions": ["ssf"]
+  },
+  "application/vnd.ericsson.quickcall": {
+    "source": "iana"
+  },
+  "application/vnd.espass-espass+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.eszigno3+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["es3","et3"]
+  },
+  "application/vnd.etsi.aoc+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.asic-e+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.etsi.asic-s+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.etsi.cug+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvcommand+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvdiscovery+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvprofile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvsad-bc+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvsad-cod+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvsad-npvr+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvservice+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvsync+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.iptvueprofile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.mcid+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.mheg5": {
+    "source": "iana"
+  },
+  "application/vnd.etsi.overload-control-policy-dataset+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.pstn+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.sci+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.simservs+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.timestamp-token": {
+    "source": "iana"
+  },
+  "application/vnd.etsi.tsl+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.etsi.tsl.der": {
+    "source": "iana"
+  },
+  "application/vnd.eu.kasparian.car+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.eudora.data": {
+    "source": "iana"
+  },
+  "application/vnd.evolv.ecig.profile": {
+    "source": "iana"
+  },
+  "application/vnd.evolv.ecig.settings": {
+    "source": "iana"
+  },
+  "application/vnd.evolv.ecig.theme": {
+    "source": "iana"
+  },
+  "application/vnd.exstream-empower+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.exstream-package": {
+    "source": "iana"
+  },
+  "application/vnd.ezpix-album": {
+    "source": "iana",
+    "extensions": ["ez2"]
+  },
+  "application/vnd.ezpix-package": {
+    "source": "iana",
+    "extensions": ["ez3"]
+  },
+  "application/vnd.f-secure.mobile": {
+    "source": "iana"
+  },
+  "application/vnd.familysearch.gedcom+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.fastcopy-disk-image": {
+    "source": "iana"
+  },
+  "application/vnd.fdf": {
+    "source": "iana",
+    "extensions": ["fdf"]
+  },
+  "application/vnd.fdsn.mseed": {
+    "source": "iana",
+    "extensions": ["mseed"]
+  },
+  "application/vnd.fdsn.seed": {
+    "source": "iana",
+    "extensions": ["seed","dataless"]
+  },
+  "application/vnd.ffsns": {
+    "source": "iana"
+  },
+  "application/vnd.ficlab.flb+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.filmit.zfc": {
+    "source": "iana"
+  },
+  "application/vnd.fints": {
+    "source": "iana"
+  },
+  "application/vnd.firemonkeys.cloudcell": {
+    "source": "iana"
+  },
+  "application/vnd.flographit": {
+    "source": "iana",
+    "extensions": ["gph"]
+  },
+  "application/vnd.fluxtime.clip": {
+    "source": "iana",
+    "extensions": ["ftc"]
+  },
+  "application/vnd.font-fontforge-sfd": {
+    "source": "iana"
+  },
+  "application/vnd.framemaker": {
+    "source": "iana",
+    "extensions": ["fm","frame","maker","book"]
+  },
+  "application/vnd.frogans.fnc": {
+    "source": "iana",
+    "extensions": ["fnc"]
+  },
+  "application/vnd.frogans.ltf": {
+    "source": "iana",
+    "extensions": ["ltf"]
+  },
+  "application/vnd.fsc.weblaunch": {
+    "source": "iana",
+    "extensions": ["fsc"]
+  },
+  "application/vnd.fujifilm.fb.docuworks": {
+    "source": "iana"
+  },
+  "application/vnd.fujifilm.fb.docuworks.binder": {
+    "source": "iana"
+  },
+  "application/vnd.fujifilm.fb.docuworks.container": {
+    "source": "iana"
+  },
+  "application/vnd.fujifilm.fb.jfi+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.fujitsu.oasys": {
+    "source": "iana",
+    "extensions": ["oas"]
+  },
+  "application/vnd.fujitsu.oasys2": {
+    "source": "iana",
+    "extensions": ["oa2"]
+  },
+  "application/vnd.fujitsu.oasys3": {
+    "source": "iana",
+    "extensions": ["oa3"]
+  },
+  "application/vnd.fujitsu.oasysgp": {
+    "source": "iana",
+    "extensions": ["fg5"]
+  },
+  "application/vnd.fujitsu.oasysprs": {
+    "source": "iana",
+    "extensions": ["bh2"]
+  },
+  "application/vnd.fujixerox.art-ex": {
+    "source": "iana"
+  },
+  "application/vnd.fujixerox.art4": {
+    "source": "iana"
+  },
+  "application/vnd.fujixerox.ddd": {
+    "source": "iana",
+    "extensions": ["ddd"]
+  },
+  "application/vnd.fujixerox.docuworks": {
+    "source": "iana",
+    "extensions": ["xdw"]
+  },
+  "application/vnd.fujixerox.docuworks.binder": {
+    "source": "iana",
+    "extensions": ["xbd"]
+  },
+  "application/vnd.fujixerox.docuworks.container": {
+    "source": "iana"
+  },
+  "application/vnd.fujixerox.hbpl": {
+    "source": "iana"
+  },
+  "application/vnd.fut-misnet": {
+    "source": "iana"
+  },
+  "application/vnd.futoin+cbor": {
+    "source": "iana"
+  },
+  "application/vnd.futoin+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.fuzzysheet": {
+    "source": "iana",
+    "extensions": ["fzs"]
+  },
+  "application/vnd.genomatix.tuxedo": {
+    "source": "iana",
+    "extensions": ["txd"]
+  },
+  "application/vnd.gentics.grd+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.geo+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.geocube+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.geogebra.file": {
+    "source": "iana",
+    "extensions": ["ggb"]
+  },
+  "application/vnd.geogebra.slides": {
+    "source": "iana"
+  },
+  "application/vnd.geogebra.tool": {
+    "source": "iana",
+    "extensions": ["ggt"]
+  },
+  "application/vnd.geometry-explorer": {
+    "source": "iana",
+    "extensions": ["gex","gre"]
+  },
+  "application/vnd.geonext": {
+    "source": "iana",
+    "extensions": ["gxt"]
+  },
+  "application/vnd.geoplan": {
+    "source": "iana",
+    "extensions": ["g2w"]
+  },
+  "application/vnd.geospace": {
+    "source": "iana",
+    "extensions": ["g3w"]
+  },
+  "application/vnd.gerber": {
+    "source": "iana"
+  },
+  "application/vnd.globalplatform.card-content-mgt": {
+    "source": "iana"
+  },
+  "application/vnd.globalplatform.card-content-mgt-response": {
+    "source": "iana"
+  },
+  "application/vnd.gmx": {
+    "source": "iana",
+    "extensions": ["gmx"]
+  },
+  "application/vnd.google-apps.document": {
+    "compressible": false,
+    "extensions": ["gdoc"]
+  },
+  "application/vnd.google-apps.presentation": {
+    "compressible": false,
+    "extensions": ["gslides"]
+  },
+  "application/vnd.google-apps.spreadsheet": {
+    "compressible": false,
+    "extensions": ["gsheet"]
+  },
+  "application/vnd.google-earth.kml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["kml"]
+  },
+  "application/vnd.google-earth.kmz": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["kmz"]
+  },
+  "application/vnd.gov.sk.e-form+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.gov.sk.e-form+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.gov.sk.xmldatacontainer+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.grafeq": {
+    "source": "iana",
+    "extensions": ["gqf","gqs"]
+  },
+  "application/vnd.gridmp": {
+    "source": "iana"
+  },
+  "application/vnd.groove-account": {
+    "source": "iana",
+    "extensions": ["gac"]
+  },
+  "application/vnd.groove-help": {
+    "source": "iana",
+    "extensions": ["ghf"]
+  },
+  "application/vnd.groove-identity-message": {
+    "source": "iana",
+    "extensions": ["gim"]
+  },
+  "application/vnd.groove-injector": {
+    "source": "iana",
+    "extensions": ["grv"]
+  },
+  "application/vnd.groove-tool-message": {
+    "source": "iana",
+    "extensions": ["gtm"]
+  },
+  "application/vnd.groove-tool-template": {
+    "source": "iana",
+    "extensions": ["tpl"]
+  },
+  "application/vnd.groove-vcard": {
+    "source": "iana",
+    "extensions": ["vcg"]
+  },
+  "application/vnd.hal+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.hal+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["hal"]
+  },
+  "application/vnd.handheld-entertainment+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["zmm"]
+  },
+  "application/vnd.hbci": {
+    "source": "iana",
+    "extensions": ["hbci"]
+  },
+  "application/vnd.hc+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.hcl-bireports": {
+    "source": "iana"
+  },
+  "application/vnd.hdt": {
+    "source": "iana"
+  },
+  "application/vnd.heroku+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.hhe.lesson-player": {
+    "source": "iana",
+    "extensions": ["les"]
+  },
+  "application/vnd.hl7cda+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/vnd.hl7v2+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/vnd.hp-hpgl": {
+    "source": "iana",
+    "extensions": ["hpgl"]
+  },
+  "application/vnd.hp-hpid": {
+    "source": "iana",
+    "extensions": ["hpid"]
+  },
+  "application/vnd.hp-hps": {
+    "source": "iana",
+    "extensions": ["hps"]
+  },
+  "application/vnd.hp-jlyt": {
+    "source": "iana",
+    "extensions": ["jlt"]
+  },
+  "application/vnd.hp-pcl": {
+    "source": "iana",
+    "extensions": ["pcl"]
+  },
+  "application/vnd.hp-pclxl": {
+    "source": "iana",
+    "extensions": ["pclxl"]
+  },
+  "application/vnd.httphone": {
+    "source": "iana"
+  },
+  "application/vnd.hydrostatix.sof-data": {
+    "source": "iana",
+    "extensions": ["sfd-hdstx"]
+  },
+  "application/vnd.hyper+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.hyper-item+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.hyperdrive+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.hzn-3d-crossword": {
+    "source": "iana"
+  },
+  "application/vnd.ibm.afplinedata": {
+    "source": "iana"
+  },
+  "application/vnd.ibm.electronic-media": {
+    "source": "iana"
+  },
+  "application/vnd.ibm.minipay": {
+    "source": "iana",
+    "extensions": ["mpy"]
+  },
+  "application/vnd.ibm.modcap": {
+    "source": "iana",
+    "extensions": ["afp","listafp","list3820"]
+  },
+  "application/vnd.ibm.rights-management": {
+    "source": "iana",
+    "extensions": ["irm"]
+  },
+  "application/vnd.ibm.secure-container": {
+    "source": "iana",
+    "extensions": ["sc"]
+  },
+  "application/vnd.iccprofile": {
+    "source": "iana",
+    "extensions": ["icc","icm"]
+  },
+  "application/vnd.ieee.1905": {
+    "source": "iana"
+  },
+  "application/vnd.igloader": {
+    "source": "iana",
+    "extensions": ["igl"]
+  },
+  "application/vnd.imagemeter.folder+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.imagemeter.image+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.immervision-ivp": {
+    "source": "iana",
+    "extensions": ["ivp"]
+  },
+  "application/vnd.immervision-ivu": {
+    "source": "iana",
+    "extensions": ["ivu"]
+  },
+  "application/vnd.ims.imsccv1p1": {
+    "source": "iana"
+  },
+  "application/vnd.ims.imsccv1p2": {
+    "source": "iana"
+  },
+  "application/vnd.ims.imsccv1p3": {
+    "source": "iana"
+  },
+  "application/vnd.ims.lis.v2.result+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ims.lti.v2.toolconsumerprofile+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ims.lti.v2.toolproxy+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ims.lti.v2.toolproxy.id+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ims.lti.v2.toolsettings+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ims.lti.v2.toolsettings.simple+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.informedcontrol.rms+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.informix-visionary": {
+    "source": "iana"
+  },
+  "application/vnd.infotech.project": {
+    "source": "iana"
+  },
+  "application/vnd.infotech.project+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.innopath.wamp.notification": {
+    "source": "iana"
+  },
+  "application/vnd.insors.igm": {
+    "source": "iana",
+    "extensions": ["igm"]
+  },
+  "application/vnd.intercon.formnet": {
+    "source": "iana",
+    "extensions": ["xpw","xpx"]
+  },
+  "application/vnd.intergeo": {
+    "source": "iana",
+    "extensions": ["i2g"]
+  },
+  "application/vnd.intertrust.digibox": {
+    "source": "iana"
+  },
+  "application/vnd.intertrust.nncp": {
+    "source": "iana"
+  },
+  "application/vnd.intu.qbo": {
+    "source": "iana",
+    "extensions": ["qbo"]
+  },
+  "application/vnd.intu.qfx": {
+    "source": "iana",
+    "extensions": ["qfx"]
+  },
+  "application/vnd.iptc.g2.catalogitem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.iptc.g2.conceptitem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.iptc.g2.knowledgeitem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.iptc.g2.newsitem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.iptc.g2.newsmessage+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.iptc.g2.packageitem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.iptc.g2.planningitem+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ipunplugged.rcprofile": {
+    "source": "iana",
+    "extensions": ["rcprofile"]
+  },
+  "application/vnd.irepository.package+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["irp"]
+  },
+  "application/vnd.is-xpr": {
+    "source": "iana",
+    "extensions": ["xpr"]
+  },
+  "application/vnd.isac.fcs": {
+    "source": "iana",
+    "extensions": ["fcs"]
+  },
+  "application/vnd.iso11783-10+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.jam": {
+    "source": "iana",
+    "extensions": ["jam"]
+  },
+  "application/vnd.japannet-directory-service": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-jpnstore-wakeup": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-payment-wakeup": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-registration": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-registration-wakeup": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-setstore-wakeup": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-verification": {
+    "source": "iana"
+  },
+  "application/vnd.japannet-verification-wakeup": {
+    "source": "iana"
+  },
+  "application/vnd.jcp.javame.midlet-rms": {
+    "source": "iana",
+    "extensions": ["rms"]
+  },
+  "application/vnd.jisp": {
+    "source": "iana",
+    "extensions": ["jisp"]
+  },
+  "application/vnd.joost.joda-archive": {
+    "source": "iana",
+    "extensions": ["joda"]
+  },
+  "application/vnd.jsk.isdn-ngn": {
+    "source": "iana"
+  },
+  "application/vnd.kahootz": {
+    "source": "iana",
+    "extensions": ["ktz","ktr"]
+  },
+  "application/vnd.kde.karbon": {
+    "source": "iana",
+    "extensions": ["karbon"]
+  },
+  "application/vnd.kde.kchart": {
+    "source": "iana",
+    "extensions": ["chrt"]
+  },
+  "application/vnd.kde.kformula": {
+    "source": "iana",
+    "extensions": ["kfo"]
+  },
+  "application/vnd.kde.kivio": {
+    "source": "iana",
+    "extensions": ["flw"]
+  },
+  "application/vnd.kde.kontour": {
+    "source": "iana",
+    "extensions": ["kon"]
+  },
+  "application/vnd.kde.kpresenter": {
+    "source": "iana",
+    "extensions": ["kpr","kpt"]
+  },
+  "application/vnd.kde.kspread": {
+    "source": "iana",
+    "extensions": ["ksp"]
+  },
+  "application/vnd.kde.kword": {
+    "source": "iana",
+    "extensions": ["kwd","kwt"]
+  },
+  "application/vnd.kenameaapp": {
+    "source": "iana",
+    "extensions": ["htke"]
+  },
+  "application/vnd.kidspiration": {
+    "source": "iana",
+    "extensions": ["kia"]
+  },
+  "application/vnd.kinar": {
+    "source": "iana",
+    "extensions": ["kne","knp"]
+  },
+  "application/vnd.koan": {
+    "source": "iana",
+    "extensions": ["skp","skd","skt","skm"]
+  },
+  "application/vnd.kodak-descriptor": {
+    "source": "iana",
+    "extensions": ["sse"]
+  },
+  "application/vnd.las": {
+    "source": "iana"
+  },
+  "application/vnd.las.las+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.las.las+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["lasxml"]
+  },
+  "application/vnd.laszip": {
+    "source": "iana"
+  },
+  "application/vnd.leap+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.liberty-request+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.llamagraphics.life-balance.desktop": {
+    "source": "iana",
+    "extensions": ["lbd"]
+  },
+  "application/vnd.llamagraphics.life-balance.exchange+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["lbe"]
+  },
+  "application/vnd.logipipe.circuit+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.loom": {
+    "source": "iana"
+  },
+  "application/vnd.lotus-1-2-3": {
+    "source": "iana",
+    "extensions": ["123"]
+  },
+  "application/vnd.lotus-approach": {
+    "source": "iana",
+    "extensions": ["apr"]
+  },
+  "application/vnd.lotus-freelance": {
+    "source": "iana",
+    "extensions": ["pre"]
+  },
+  "application/vnd.lotus-notes": {
+    "source": "iana",
+    "extensions": ["nsf"]
+  },
+  "application/vnd.lotus-organizer": {
+    "source": "iana",
+    "extensions": ["org"]
+  },
+  "application/vnd.lotus-screencam": {
+    "source": "iana",
+    "extensions": ["scm"]
+  },
+  "application/vnd.lotus-wordpro": {
+    "source": "iana",
+    "extensions": ["lwp"]
+  },
+  "application/vnd.macports.portpkg": {
+    "source": "iana",
+    "extensions": ["portpkg"]
+  },
+  "application/vnd.mapbox-vector-tile": {
+    "source": "iana",
+    "extensions": ["mvt"]
+  },
+  "application/vnd.marlin.drm.actiontoken+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.marlin.drm.conftoken+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.marlin.drm.license+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.marlin.drm.mdcf": {
+    "source": "iana"
+  },
+  "application/vnd.mason+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.maxar.archive.3tz+zip": {
+    "source": "iana",
+    "compressible": false
+  },
+  "application/vnd.maxmind.maxmind-db": {
+    "source": "iana"
+  },
+  "application/vnd.mcd": {
+    "source": "iana",
+    "extensions": ["mcd"]
+  },
+  "application/vnd.medcalcdata": {
+    "source": "iana",
+    "extensions": ["mc1"]
+  },
+  "application/vnd.mediastation.cdkey": {
+    "source": "iana",
+    "extensions": ["cdkey"]
+  },
+  "application/vnd.meridian-slingshot": {
+    "source": "iana"
+  },
+  "application/vnd.mfer": {
+    "source": "iana",
+    "extensions": ["mwf"]
+  },
+  "application/vnd.mfmp": {
+    "source": "iana",
+    "extensions": ["mfm"]
+  },
+  "application/vnd.micro+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.micrografx.flo": {
+    "source": "iana",
+    "extensions": ["flo"]
+  },
+  "application/vnd.micrografx.igx": {
+    "source": "iana",
+    "extensions": ["igx"]
+  },
+  "application/vnd.microsoft.portable-executable": {
+    "source": "iana"
+  },
+  "application/vnd.microsoft.windows.thumbnail-cache": {
+    "source": "iana"
+  },
+  "application/vnd.miele+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.mif": {
+    "source": "iana",
+    "extensions": ["mif"]
+  },
+  "application/vnd.minisoft-hp3000-save": {
+    "source": "iana"
+  },
+  "application/vnd.mitsubishi.misty-guard.trustweb": {
+    "source": "iana"
+  },
+  "application/vnd.mobius.daf": {
+    "source": "iana",
+    "extensions": ["daf"]
+  },
+  "application/vnd.mobius.dis": {
+    "source": "iana",
+    "extensions": ["dis"]
+  },
+  "application/vnd.mobius.mbk": {
+    "source": "iana",
+    "extensions": ["mbk"]
+  },
+  "application/vnd.mobius.mqy": {
+    "source": "iana",
+    "extensions": ["mqy"]
+  },
+  "application/vnd.mobius.msl": {
+    "source": "iana",
+    "extensions": ["msl"]
+  },
+  "application/vnd.mobius.plc": {
+    "source": "iana",
+    "extensions": ["plc"]
+  },
+  "application/vnd.mobius.txf": {
+    "source": "iana",
+    "extensions": ["txf"]
+  },
+  "application/vnd.mophun.application": {
+    "source": "iana",
+    "extensions": ["mpn"]
+  },
+  "application/vnd.mophun.certificate": {
+    "source": "iana",
+    "extensions": ["mpc"]
+  },
+  "application/vnd.motorola.flexsuite": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.flexsuite.adsi": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.flexsuite.fis": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.flexsuite.gotap": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.flexsuite.kmr": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.flexsuite.ttc": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.flexsuite.wem": {
+    "source": "iana"
+  },
+  "application/vnd.motorola.iprm": {
+    "source": "iana"
+  },
+  "application/vnd.mozilla.xul+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xul"]
+  },
+  "application/vnd.ms-3mfdocument": {
+    "source": "iana"
+  },
+  "application/vnd.ms-artgalry": {
+    "source": "iana",
+    "extensions": ["cil"]
+  },
+  "application/vnd.ms-asf": {
+    "source": "iana"
+  },
+  "application/vnd.ms-cab-compressed": {
+    "source": "iana",
+    "extensions": ["cab"]
+  },
+  "application/vnd.ms-color.iccprofile": {
+    "source": "apache"
+  },
+  "application/vnd.ms-excel": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["xls","xlm","xla","xlc","xlt","xlw"]
+  },
+  "application/vnd.ms-excel.addin.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["xlam"]
+  },
+  "application/vnd.ms-excel.sheet.binary.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["xlsb"]
+  },
+  "application/vnd.ms-excel.sheet.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["xlsm"]
+  },
+  "application/vnd.ms-excel.template.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["xltm"]
+  },
+  "application/vnd.ms-fontobject": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["eot"]
+  },
+  "application/vnd.ms-htmlhelp": {
+    "source": "iana",
+    "extensions": ["chm"]
+  },
+  "application/vnd.ms-ims": {
+    "source": "iana",
+    "extensions": ["ims"]
+  },
+  "application/vnd.ms-lrm": {
+    "source": "iana",
+    "extensions": ["lrm"]
+  },
+  "application/vnd.ms-office.activex+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ms-officetheme": {
+    "source": "iana",
+    "extensions": ["thmx"]
+  },
+  "application/vnd.ms-opentype": {
+    "source": "apache",
+    "compressible": true
+  },
+  "application/vnd.ms-outlook": {
+    "compressible": false,
+    "extensions": ["msg"]
+  },
+  "application/vnd.ms-package.obfuscated-opentype": {
+    "source": "apache"
+  },
+  "application/vnd.ms-pki.seccat": {
+    "source": "apache",
+    "extensions": ["cat"]
+  },
+  "application/vnd.ms-pki.stl": {
+    "source": "apache",
+    "extensions": ["stl"]
+  },
+  "application/vnd.ms-playready.initiator+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ms-powerpoint": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["ppt","pps","pot"]
+  },
+  "application/vnd.ms-powerpoint.addin.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["ppam"]
+  },
+  "application/vnd.ms-powerpoint.presentation.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["pptm"]
+  },
+  "application/vnd.ms-powerpoint.slide.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["sldm"]
+  },
+  "application/vnd.ms-powerpoint.slideshow.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["ppsm"]
+  },
+  "application/vnd.ms-powerpoint.template.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["potm"]
+  },
+  "application/vnd.ms-printdevicecapabilities+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ms-printing.printticket+xml": {
+    "source": "apache",
+    "compressible": true
+  },
+  "application/vnd.ms-printschematicket+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ms-project": {
+    "source": "iana",
+    "extensions": ["mpp","mpt"]
+  },
+  "application/vnd.ms-tnef": {
+    "source": "iana"
+  },
+  "application/vnd.ms-windows.devicepairing": {
+    "source": "iana"
+  },
+  "application/vnd.ms-windows.nwprinting.oob": {
+    "source": "iana"
+  },
+  "application/vnd.ms-windows.printerpairing": {
+    "source": "iana"
+  },
+  "application/vnd.ms-windows.wsd.oob": {
+    "source": "iana"
+  },
+  "application/vnd.ms-wmdrm.lic-chlg-req": {
+    "source": "iana"
+  },
+  "application/vnd.ms-wmdrm.lic-resp": {
+    "source": "iana"
+  },
+  "application/vnd.ms-wmdrm.meter-chlg-req": {
+    "source": "iana"
+  },
+  "application/vnd.ms-wmdrm.meter-resp": {
+    "source": "iana"
+  },
+  "application/vnd.ms-word.document.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["docm"]
+  },
+  "application/vnd.ms-word.template.macroenabled.12": {
+    "source": "iana",
+    "extensions": ["dotm"]
+  },
+  "application/vnd.ms-works": {
+    "source": "iana",
+    "extensions": ["wps","wks","wcm","wdb"]
+  },
+  "application/vnd.ms-wpl": {
+    "source": "iana",
+    "extensions": ["wpl"]
+  },
+  "application/vnd.ms-xpsdocument": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["xps"]
+  },
+  "application/vnd.msa-disk-image": {
+    "source": "iana"
+  },
+  "application/vnd.mseq": {
+    "source": "iana",
+    "extensions": ["mseq"]
+  },
+  "application/vnd.msign": {
+    "source": "iana"
+  },
+  "application/vnd.multiad.creator": {
+    "source": "iana"
+  },
+  "application/vnd.multiad.creator.cif": {
+    "source": "iana"
+  },
+  "application/vnd.music-niff": {
+    "source": "iana"
+  },
+  "application/vnd.musician": {
+    "source": "iana",
+    "extensions": ["mus"]
+  },
+  "application/vnd.muvee.style": {
+    "source": "iana",
+    "extensions": ["msty"]
+  },
+  "application/vnd.mynfc": {
+    "source": "iana",
+    "extensions": ["taglet"]
+  },
+  "application/vnd.nacamar.ybrid+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.ncd.control": {
+    "source": "iana"
+  },
+  "application/vnd.ncd.reference": {
+    "source": "iana"
+  },
+  "application/vnd.nearst.inv+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.nebumind.line": {
+    "source": "iana"
+  },
+  "application/vnd.nervana": {
+    "source": "iana"
+  },
+  "application/vnd.netfpx": {
+    "source": "iana"
+  },
+  "application/vnd.neurolanguage.nlu": {
+    "source": "iana",
+    "extensions": ["nlu"]
+  },
+  "application/vnd.nimn": {
+    "source": "iana"
+  },
+  "application/vnd.nintendo.nitro.rom": {
+    "source": "iana"
+  },
+  "application/vnd.nintendo.snes.rom": {
+    "source": "iana"
+  },
+  "application/vnd.nitf": {
+    "source": "iana",
+    "extensions": ["ntf","nitf"]
+  },
+  "application/vnd.noblenet-directory": {
+    "source": "iana",
+    "extensions": ["nnd"]
+  },
+  "application/vnd.noblenet-sealer": {
+    "source": "iana",
+    "extensions": ["nns"]
+  },
+  "application/vnd.noblenet-web": {
+    "source": "iana",
+    "extensions": ["nnw"]
+  },
+  "application/vnd.nokia.catalogs": {
+    "source": "iana"
+  },
+  "application/vnd.nokia.conml+wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.nokia.conml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.nokia.iptv.config+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.nokia.isds-radio-presets": {
+    "source": "iana"
+  },
+  "application/vnd.nokia.landmark+wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.nokia.landmark+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.nokia.landmarkcollection+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.nokia.n-gage.ac+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ac"]
+  },
+  "application/vnd.nokia.n-gage.data": {
+    "source": "iana",
+    "extensions": ["ngdat"]
+  },
+  "application/vnd.nokia.n-gage.symbian.install": {
+    "source": "iana",
+    "extensions": ["n-gage"]
+  },
+  "application/vnd.nokia.ncd": {
+    "source": "iana"
+  },
+  "application/vnd.nokia.pcd+wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.nokia.pcd+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.nokia.radio-preset": {
+    "source": "iana",
+    "extensions": ["rpst"]
+  },
+  "application/vnd.nokia.radio-presets": {
+    "source": "iana",
+    "extensions": ["rpss"]
+  },
+  "application/vnd.novadigm.edm": {
+    "source": "iana",
+    "extensions": ["edm"]
+  },
+  "application/vnd.novadigm.edx": {
+    "source": "iana",
+    "extensions": ["edx"]
+  },
+  "application/vnd.novadigm.ext": {
+    "source": "iana",
+    "extensions": ["ext"]
+  },
+  "application/vnd.ntt-local.content-share": {
+    "source": "iana"
+  },
+  "application/vnd.ntt-local.file-transfer": {
+    "source": "iana"
+  },
+  "application/vnd.ntt-local.ogw_remote-access": {
+    "source": "iana"
+  },
+  "application/vnd.ntt-local.sip-ta_remote": {
+    "source": "iana"
+  },
+  "application/vnd.ntt-local.sip-ta_tcp_stream": {
+    "source": "iana"
+  },
+  "application/vnd.oasis.opendocument.chart": {
+    "source": "iana",
+    "extensions": ["odc"]
+  },
+  "application/vnd.oasis.opendocument.chart-template": {
+    "source": "iana",
+    "extensions": ["otc"]
+  },
+  "application/vnd.oasis.opendocument.database": {
+    "source": "iana",
+    "extensions": ["odb"]
+  },
+  "application/vnd.oasis.opendocument.formula": {
+    "source": "iana",
+    "extensions": ["odf"]
+  },
+  "application/vnd.oasis.opendocument.formula-template": {
+    "source": "iana",
+    "extensions": ["odft"]
+  },
+  "application/vnd.oasis.opendocument.graphics": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["odg"]
+  },
+  "application/vnd.oasis.opendocument.graphics-template": {
+    "source": "iana",
+    "extensions": ["otg"]
+  },
+  "application/vnd.oasis.opendocument.image": {
+    "source": "iana",
+    "extensions": ["odi"]
+  },
+  "application/vnd.oasis.opendocument.image-template": {
+    "source": "iana",
+    "extensions": ["oti"]
+  },
+  "application/vnd.oasis.opendocument.presentation": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["odp"]
+  },
+  "application/vnd.oasis.opendocument.presentation-template": {
+    "source": "iana",
+    "extensions": ["otp"]
+  },
+  "application/vnd.oasis.opendocument.spreadsheet": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["ods"]
+  },
+  "application/vnd.oasis.opendocument.spreadsheet-template": {
+    "source": "iana",
+    "extensions": ["ots"]
+  },
+  "application/vnd.oasis.opendocument.text": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["odt"]
+  },
+  "application/vnd.oasis.opendocument.text-master": {
+    "source": "iana",
+    "extensions": ["odm"]
+  },
+  "application/vnd.oasis.opendocument.text-template": {
+    "source": "iana",
+    "extensions": ["ott"]
+  },
+  "application/vnd.oasis.opendocument.text-web": {
+    "source": "iana",
+    "extensions": ["oth"]
+  },
+  "application/vnd.obn": {
+    "source": "iana"
+  },
+  "application/vnd.ocf+cbor": {
+    "source": "iana"
+  },
+  "application/vnd.oci.image.manifest.v1+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oftn.l10n+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.contentaccessdownload+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.contentaccessstreaming+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.cspg-hexbinary": {
+    "source": "iana"
+  },
+  "application/vnd.oipf.dae.svg+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.dae.xhtml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.mippvcontrolmessage+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.pae.gem": {
+    "source": "iana"
+  },
+  "application/vnd.oipf.spdiscovery+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.spdlist+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.ueprofile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oipf.userprofile+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.olpc-sugar": {
+    "source": "iana",
+    "extensions": ["xo"]
+  },
+  "application/vnd.oma-scws-config": {
+    "source": "iana"
+  },
+  "application/vnd.oma-scws-http-request": {
+    "source": "iana"
+  },
+  "application/vnd.oma-scws-http-response": {
+    "source": "iana"
+  },
+  "application/vnd.oma.bcast.associated-procedure-parameter+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.drm-trigger+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.imd+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.ltkm": {
+    "source": "iana"
+  },
+  "application/vnd.oma.bcast.notification+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.provisioningtrigger": {
+    "source": "iana"
+  },
+  "application/vnd.oma.bcast.sgboot": {
+    "source": "iana"
+  },
+  "application/vnd.oma.bcast.sgdd+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.sgdu": {
+    "source": "iana"
+  },
+  "application/vnd.oma.bcast.simple-symbol-container": {
+    "source": "iana"
+  },
+  "application/vnd.oma.bcast.smartcard-trigger+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.sprov+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.bcast.stkm": {
+    "source": "iana"
+  },
+  "application/vnd.oma.cab-address-book+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.cab-feature-handler+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.cab-pcc+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.cab-subs-invite+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.cab-user-prefs+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.dcd": {
+    "source": "iana"
+  },
+  "application/vnd.oma.dcdc": {
+    "source": "iana"
+  },
+  "application/vnd.oma.dd2+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["dd2"]
+  },
+  "application/vnd.oma.drm.risd+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.group-usage-list+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.lwm2m+cbor": {
+    "source": "iana"
+  },
+  "application/vnd.oma.lwm2m+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.lwm2m+tlv": {
+    "source": "iana"
+  },
+  "application/vnd.oma.pal+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.poc.detailed-progress-report+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.poc.final-report+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.poc.groups+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.poc.invocation-descriptor+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.poc.optimized-progress-report+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.push": {
+    "source": "iana"
+  },
+  "application/vnd.oma.scidm.messages+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oma.xcap-directory+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.omads-email+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/vnd.omads-file+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/vnd.omads-folder+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/vnd.omaloc-supl-init": {
+    "source": "iana"
+  },
+  "application/vnd.onepager": {
+    "source": "iana"
+  },
+  "application/vnd.onepagertamp": {
+    "source": "iana"
+  },
+  "application/vnd.onepagertamx": {
+    "source": "iana"
+  },
+  "application/vnd.onepagertat": {
+    "source": "iana"
+  },
+  "application/vnd.onepagertatp": {
+    "source": "iana"
+  },
+  "application/vnd.onepagertatx": {
+    "source": "iana"
+  },
+  "application/vnd.openblox.game+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["obgx"]
+  },
+  "application/vnd.openblox.game-binary": {
+    "source": "iana"
+  },
+  "application/vnd.openeye.oeb": {
+    "source": "iana"
+  },
+  "application/vnd.openofficeorg.extension": {
+    "source": "apache",
+    "extensions": ["oxt"]
+  },
+  "application/vnd.openstreetmap.data+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["osm"]
+  },
+  "application/vnd.opentimestamps.ots": {
+    "source": "iana"
+  },
+  "application/vnd.openxmlformats-officedocument.custom-properties+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.customxmlproperties+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawing+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.extended-properties+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.comments+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["pptx"]
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.presprops+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slide": {
+    "source": "iana",
+    "extensions": ["sldx"]
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slide+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slideshow": {
+    "source": "iana",
+    "extensions": ["ppsx"]
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.tags+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.template": {
+    "source": "iana",
+    "extensions": ["potx"]
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["xlsx"]
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.template": {
+    "source": "iana",
+    "extensions": ["xltx"]
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.theme+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.themeoverride+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.vmldrawing": {
+    "source": "iana"
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["docx"]
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.template": {
+    "source": "iana",
+    "extensions": ["dotx"]
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-package.core-properties+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.openxmlformats-package.relationships+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oracle.resource+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.orange.indata": {
+    "source": "iana"
+  },
+  "application/vnd.osa.netdeploy": {
+    "source": "iana"
+  },
+  "application/vnd.osgeo.mapguide.package": {
+    "source": "iana",
+    "extensions": ["mgp"]
+  },
+  "application/vnd.osgi.bundle": {
+    "source": "iana"
+  },
+  "application/vnd.osgi.dp": {
+    "source": "iana",
+    "extensions": ["dp"]
+  },
+  "application/vnd.osgi.subsystem": {
+    "source": "iana",
+    "extensions": ["esa"]
+  },
+  "application/vnd.otps.ct-kip+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.oxli.countgraph": {
+    "source": "iana"
+  },
+  "application/vnd.pagerduty+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.palm": {
+    "source": "iana",
+    "extensions": ["pdb","pqa","oprc"]
+  },
+  "application/vnd.panoply": {
+    "source": "iana"
+  },
+  "application/vnd.paos.xml": {
+    "source": "iana"
+  },
+  "application/vnd.patentdive": {
+    "source": "iana"
+  },
+  "application/vnd.patientecommsdoc": {
+    "source": "iana"
+  },
+  "application/vnd.pawaafile": {
+    "source": "iana",
+    "extensions": ["paw"]
+  },
+  "application/vnd.pcos": {
+    "source": "iana"
+  },
+  "application/vnd.pg.format": {
+    "source": "iana",
+    "extensions": ["str"]
+  },
+  "application/vnd.pg.osasli": {
+    "source": "iana",
+    "extensions": ["ei6"]
+  },
+  "application/vnd.piaccess.application-licence": {
+    "source": "iana"
+  },
+  "application/vnd.picsel": {
+    "source": "iana",
+    "extensions": ["efif"]
+  },
+  "application/vnd.pmi.widget": {
+    "source": "iana",
+    "extensions": ["wg"]
+  },
+  "application/vnd.poc.group-advertisement+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.pocketlearn": {
+    "source": "iana",
+    "extensions": ["plf"]
+  },
+  "application/vnd.powerbuilder6": {
+    "source": "iana",
+    "extensions": ["pbd"]
+  },
+  "application/vnd.powerbuilder6-s": {
+    "source": "iana"
+  },
+  "application/vnd.powerbuilder7": {
+    "source": "iana"
+  },
+  "application/vnd.powerbuilder7-s": {
+    "source": "iana"
+  },
+  "application/vnd.powerbuilder75": {
+    "source": "iana"
+  },
+  "application/vnd.powerbuilder75-s": {
+    "source": "iana"
+  },
+  "application/vnd.preminet": {
+    "source": "iana"
+  },
+  "application/vnd.previewsystems.box": {
+    "source": "iana",
+    "extensions": ["box"]
+  },
+  "application/vnd.proteus.magazine": {
+    "source": "iana",
+    "extensions": ["mgz"]
+  },
+  "application/vnd.psfs": {
+    "source": "iana"
+  },
+  "application/vnd.publishare-delta-tree": {
+    "source": "iana",
+    "extensions": ["qps"]
+  },
+  "application/vnd.pvi.ptid1": {
+    "source": "iana",
+    "extensions": ["ptid"]
+  },
+  "application/vnd.pwg-multiplexed": {
+    "source": "iana"
+  },
+  "application/vnd.pwg-xhtml-print+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.qualcomm.brew-app-res": {
+    "source": "iana"
+  },
+  "application/vnd.quarantainenet": {
+    "source": "iana"
+  },
+  "application/vnd.quark.quarkxpress": {
+    "source": "iana",
+    "extensions": ["qxd","qxt","qwd","qwt","qxl","qxb"]
+  },
+  "application/vnd.quobject-quoxdocument": {
+    "source": "iana"
+  },
+  "application/vnd.radisys.moml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-audit+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-audit-conf+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-audit-conn+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-audit-dialog+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-audit-stream+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-conf+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog-base+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog-fax-detect+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog-fax-sendrecv+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog-group+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog-speech+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.radisys.msml-dialog-transform+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.rainstor.data": {
+    "source": "iana"
+  },
+  "application/vnd.rapid": {
+    "source": "iana"
+  },
+  "application/vnd.rar": {
+    "source": "iana",
+    "extensions": ["rar"]
+  },
+  "application/vnd.realvnc.bed": {
+    "source": "iana",
+    "extensions": ["bed"]
+  },
+  "application/vnd.recordare.musicxml": {
+    "source": "iana",
+    "extensions": ["mxl"]
+  },
+  "application/vnd.recordare.musicxml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["musicxml"]
+  },
+  "application/vnd.renlearn.rlprint": {
+    "source": "iana"
+  },
+  "application/vnd.resilient.logic": {
+    "source": "iana"
+  },
+  "application/vnd.restful+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.rig.cryptonote": {
+    "source": "iana",
+    "extensions": ["cryptonote"]
+  },
+  "application/vnd.rim.cod": {
+    "source": "apache",
+    "extensions": ["cod"]
+  },
+  "application/vnd.rn-realmedia": {
+    "source": "apache",
+    "extensions": ["rm"]
+  },
+  "application/vnd.rn-realmedia-vbr": {
+    "source": "apache",
+    "extensions": ["rmvb"]
+  },
+  "application/vnd.route66.link66+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["link66"]
+  },
+  "application/vnd.rs-274x": {
+    "source": "iana"
+  },
+  "application/vnd.ruckus.download": {
+    "source": "iana"
+  },
+  "application/vnd.s3sms": {
+    "source": "iana"
+  },
+  "application/vnd.sailingtracker.track": {
+    "source": "iana",
+    "extensions": ["st"]
+  },
+  "application/vnd.sar": {
+    "source": "iana"
+  },
+  "application/vnd.sbm.cid": {
+    "source": "iana"
+  },
+  "application/vnd.sbm.mid2": {
+    "source": "iana"
+  },
+  "application/vnd.scribus": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.3df": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.csf": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.doc": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.eml": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.mht": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.net": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.ppt": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.tiff": {
+    "source": "iana"
+  },
+  "application/vnd.sealed.xls": {
+    "source": "iana"
+  },
+  "application/vnd.sealedmedia.softseal.html": {
+    "source": "iana"
+  },
+  "application/vnd.sealedmedia.softseal.pdf": {
+    "source": "iana"
+  },
+  "application/vnd.seemail": {
+    "source": "iana",
+    "extensions": ["see"]
+  },
+  "application/vnd.seis+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.sema": {
+    "source": "iana",
+    "extensions": ["sema"]
+  },
+  "application/vnd.semd": {
+    "source": "iana",
+    "extensions": ["semd"]
+  },
+  "application/vnd.semf": {
+    "source": "iana",
+    "extensions": ["semf"]
+  },
+  "application/vnd.shade-save-file": {
+    "source": "iana"
+  },
+  "application/vnd.shana.informed.formdata": {
+    "source": "iana",
+    "extensions": ["ifm"]
+  },
+  "application/vnd.shana.informed.formtemplate": {
+    "source": "iana",
+    "extensions": ["itp"]
+  },
+  "application/vnd.shana.informed.interchange": {
+    "source": "iana",
+    "extensions": ["iif"]
+  },
+  "application/vnd.shana.informed.package": {
+    "source": "iana",
+    "extensions": ["ipk"]
+  },
+  "application/vnd.shootproof+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.shopkick+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.shp": {
+    "source": "iana"
+  },
+  "application/vnd.shx": {
+    "source": "iana"
+  },
+  "application/vnd.sigrok.session": {
+    "source": "iana"
+  },
+  "application/vnd.simtech-mindmapper": {
+    "source": "iana",
+    "extensions": ["twd","twds"]
+  },
+  "application/vnd.siren+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.smaf": {
+    "source": "iana",
+    "extensions": ["mmf"]
+  },
+  "application/vnd.smart.notebook": {
+    "source": "iana"
+  },
+  "application/vnd.smart.teacher": {
+    "source": "iana",
+    "extensions": ["teacher"]
+  },
+  "application/vnd.snesdev-page-table": {
+    "source": "iana"
+  },
+  "application/vnd.software602.filler.form+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["fo"]
+  },
+  "application/vnd.software602.filler.form-xml-zip": {
+    "source": "iana"
+  },
+  "application/vnd.solent.sdkm+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["sdkm","sdkd"]
+  },
+  "application/vnd.spotfire.dxp": {
+    "source": "iana",
+    "extensions": ["dxp"]
+  },
+  "application/vnd.spotfire.sfs": {
+    "source": "iana",
+    "extensions": ["sfs"]
+  },
+  "application/vnd.sqlite3": {
+    "source": "iana"
+  },
+  "application/vnd.sss-cod": {
+    "source": "iana"
+  },
+  "application/vnd.sss-dtf": {
+    "source": "iana"
+  },
+  "application/vnd.sss-ntf": {
+    "source": "iana"
+  },
+  "application/vnd.stardivision.calc": {
+    "source": "apache",
+    "extensions": ["sdc"]
+  },
+  "application/vnd.stardivision.draw": {
+    "source": "apache",
+    "extensions": ["sda"]
+  },
+  "application/vnd.stardivision.impress": {
+    "source": "apache",
+    "extensions": ["sdd"]
+  },
+  "application/vnd.stardivision.math": {
+    "source": "apache",
+    "extensions": ["smf"]
+  },
+  "application/vnd.stardivision.writer": {
+    "source": "apache",
+    "extensions": ["sdw","vor"]
+  },
+  "application/vnd.stardivision.writer-global": {
+    "source": "apache",
+    "extensions": ["sgl"]
+  },
+  "application/vnd.stepmania.package": {
+    "source": "iana",
+    "extensions": ["smzip"]
+  },
+  "application/vnd.stepmania.stepchart": {
+    "source": "iana",
+    "extensions": ["sm"]
+  },
+  "application/vnd.street-stream": {
+    "source": "iana"
+  },
+  "application/vnd.sun.wadl+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["wadl"]
+  },
+  "application/vnd.sun.xml.calc": {
+    "source": "apache",
+    "extensions": ["sxc"]
+  },
+  "application/vnd.sun.xml.calc.template": {
+    "source": "apache",
+    "extensions": ["stc"]
+  },
+  "application/vnd.sun.xml.draw": {
+    "source": "apache",
+    "extensions": ["sxd"]
+  },
+  "application/vnd.sun.xml.draw.template": {
+    "source": "apache",
+    "extensions": ["std"]
+  },
+  "application/vnd.sun.xml.impress": {
+    "source": "apache",
+    "extensions": ["sxi"]
+  },
+  "application/vnd.sun.xml.impress.template": {
+    "source": "apache",
+    "extensions": ["sti"]
+  },
+  "application/vnd.sun.xml.math": {
+    "source": "apache",
+    "extensions": ["sxm"]
+  },
+  "application/vnd.sun.xml.writer": {
+    "source": "apache",
+    "extensions": ["sxw"]
+  },
+  "application/vnd.sun.xml.writer.global": {
+    "source": "apache",
+    "extensions": ["sxg"]
+  },
+  "application/vnd.sun.xml.writer.template": {
+    "source": "apache",
+    "extensions": ["stw"]
+  },
+  "application/vnd.sus-calendar": {
+    "source": "iana",
+    "extensions": ["sus","susp"]
+  },
+  "application/vnd.svd": {
+    "source": "iana",
+    "extensions": ["svd"]
+  },
+  "application/vnd.swiftview-ics": {
+    "source": "iana"
+  },
+  "application/vnd.sycle+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.syft+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.symbian.install": {
+    "source": "apache",
+    "extensions": ["sis","sisx"]
+  },
+  "application/vnd.syncml+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["xsm"]
+  },
+  "application/vnd.syncml.dm+wbxml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "extensions": ["bdm"]
+  },
+  "application/vnd.syncml.dm+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["xdm"]
+  },
+  "application/vnd.syncml.dm.notification": {
+    "source": "iana"
+  },
+  "application/vnd.syncml.dmddf+wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.syncml.dmddf+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["ddf"]
+  },
+  "application/vnd.syncml.dmtnds+wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.syncml.dmtnds+xml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true
+  },
+  "application/vnd.syncml.ds.notification": {
+    "source": "iana"
+  },
+  "application/vnd.tableschema+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.tao.intent-module-archive": {
+    "source": "iana",
+    "extensions": ["tao"]
+  },
+  "application/vnd.tcpdump.pcap": {
+    "source": "iana",
+    "extensions": ["pcap","cap","dmp"]
+  },
+  "application/vnd.think-cell.ppttc+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.tmd.mediaflex.api+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.tml": {
+    "source": "iana"
+  },
+  "application/vnd.tmobile-livetv": {
+    "source": "iana",
+    "extensions": ["tmo"]
+  },
+  "application/vnd.tri.onesource": {
+    "source": "iana"
+  },
+  "application/vnd.trid.tpt": {
+    "source": "iana",
+    "extensions": ["tpt"]
+  },
+  "application/vnd.triscape.mxs": {
+    "source": "iana",
+    "extensions": ["mxs"]
+  },
+  "application/vnd.trueapp": {
+    "source": "iana",
+    "extensions": ["tra"]
+  },
+  "application/vnd.truedoc": {
+    "source": "iana"
+  },
+  "application/vnd.ubisoft.webplayer": {
+    "source": "iana"
+  },
+  "application/vnd.ufdl": {
+    "source": "iana",
+    "extensions": ["ufd","ufdl"]
+  },
+  "application/vnd.uiq.theme": {
+    "source": "iana",
+    "extensions": ["utz"]
+  },
+  "application/vnd.umajin": {
+    "source": "iana",
+    "extensions": ["umj"]
+  },
+  "application/vnd.unity": {
+    "source": "iana",
+    "extensions": ["unityweb"]
+  },
+  "application/vnd.uoml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["uoml"]
+  },
+  "application/vnd.uplanet.alert": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.alert-wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.bearer-choice": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.bearer-choice-wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.cacheop": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.cacheop-wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.channel": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.channel-wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.list": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.list-wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.listcmd": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.listcmd-wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.uplanet.signal": {
+    "source": "iana"
+  },
+  "application/vnd.uri-map": {
+    "source": "iana"
+  },
+  "application/vnd.valve.source.material": {
+    "source": "iana"
+  },
+  "application/vnd.vcx": {
+    "source": "iana",
+    "extensions": ["vcx"]
+  },
+  "application/vnd.vd-study": {
+    "source": "iana"
+  },
+  "application/vnd.vectorworks": {
+    "source": "iana"
+  },
+  "application/vnd.vel+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.verimatrix.vcas": {
+    "source": "iana"
+  },
+  "application/vnd.veritone.aion+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.veryant.thin": {
+    "source": "iana"
+  },
+  "application/vnd.ves.encrypted": {
+    "source": "iana"
+  },
+  "application/vnd.vidsoft.vidconference": {
+    "source": "iana"
+  },
+  "application/vnd.visio": {
+    "source": "iana",
+    "extensions": ["vsd","vst","vss","vsw"]
+  },
+  "application/vnd.visionary": {
+    "source": "iana",
+    "extensions": ["vis"]
+  },
+  "application/vnd.vividence.scriptfile": {
+    "source": "iana"
+  },
+  "application/vnd.vsf": {
+    "source": "iana",
+    "extensions": ["vsf"]
+  },
+  "application/vnd.wap.sic": {
+    "source": "iana"
+  },
+  "application/vnd.wap.slc": {
+    "source": "iana"
+  },
+  "application/vnd.wap.wbxml": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "extensions": ["wbxml"]
+  },
+  "application/vnd.wap.wmlc": {
+    "source": "iana",
+    "extensions": ["wmlc"]
+  },
+  "application/vnd.wap.wmlscriptc": {
+    "source": "iana",
+    "extensions": ["wmlsc"]
+  },
+  "application/vnd.webturbo": {
+    "source": "iana",
+    "extensions": ["wtb"]
+  },
+  "application/vnd.wfa.dpp": {
+    "source": "iana"
+  },
+  "application/vnd.wfa.p2p": {
+    "source": "iana"
+  },
+  "application/vnd.wfa.wsc": {
+    "source": "iana"
+  },
+  "application/vnd.windows.devicepairing": {
+    "source": "iana"
+  },
+  "application/vnd.wmc": {
+    "source": "iana"
+  },
+  "application/vnd.wmf.bootstrap": {
+    "source": "iana"
+  },
+  "application/vnd.wolfram.mathematica": {
+    "source": "iana"
+  },
+  "application/vnd.wolfram.mathematica.package": {
+    "source": "iana"
+  },
+  "application/vnd.wolfram.player": {
+    "source": "iana",
+    "extensions": ["nbp"]
+  },
+  "application/vnd.wordperfect": {
+    "source": "iana",
+    "extensions": ["wpd"]
+  },
+  "application/vnd.wqd": {
+    "source": "iana",
+    "extensions": ["wqd"]
+  },
+  "application/vnd.wrq-hp3000-labelled": {
+    "source": "iana"
+  },
+  "application/vnd.wt.stf": {
+    "source": "iana",
+    "extensions": ["stf"]
+  },
+  "application/vnd.wv.csp+wbxml": {
+    "source": "iana"
+  },
+  "application/vnd.wv.csp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.wv.ssp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.xacml+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.xara": {
+    "source": "iana",
+    "extensions": ["xar"]
+  },
+  "application/vnd.xfdl": {
+    "source": "iana",
+    "extensions": ["xfdl"]
+  },
+  "application/vnd.xfdl.webform": {
+    "source": "iana"
+  },
+  "application/vnd.xmi+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vnd.xmpie.cpkg": {
+    "source": "iana"
+  },
+  "application/vnd.xmpie.dpkg": {
+    "source": "iana"
+  },
+  "application/vnd.xmpie.plan": {
+    "source": "iana"
+  },
+  "application/vnd.xmpie.ppkg": {
+    "source": "iana"
+  },
+  "application/vnd.xmpie.xlim": {
+    "source": "iana"
+  },
+  "application/vnd.yamaha.hv-dic": {
+    "source": "iana",
+    "extensions": ["hvd"]
+  },
+  "application/vnd.yamaha.hv-script": {
+    "source": "iana",
+    "extensions": ["hvs"]
+  },
+  "application/vnd.yamaha.hv-voice": {
+    "source": "iana",
+    "extensions": ["hvp"]
+  },
+  "application/vnd.yamaha.openscoreformat": {
+    "source": "iana",
+    "extensions": ["osf"]
+  },
+  "application/vnd.yamaha.openscoreformat.osfpvg+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["osfpvg"]
+  },
+  "application/vnd.yamaha.remote-setup": {
+    "source": "iana"
+  },
+  "application/vnd.yamaha.smaf-audio": {
+    "source": "iana",
+    "extensions": ["saf"]
+  },
+  "application/vnd.yamaha.smaf-phrase": {
+    "source": "iana",
+    "extensions": ["spf"]
+  },
+  "application/vnd.yamaha.through-ngn": {
+    "source": "iana"
+  },
+  "application/vnd.yamaha.tunnel-udpencap": {
+    "source": "iana"
+  },
+  "application/vnd.yaoweme": {
+    "source": "iana"
+  },
+  "application/vnd.yellowriver-custom-menu": {
+    "source": "iana",
+    "extensions": ["cmp"]
+  },
+  "application/vnd.youtube.yt": {
+    "source": "iana"
+  },
+  "application/vnd.zul": {
+    "source": "iana",
+    "extensions": ["zir","zirz"]
+  },
+  "application/vnd.zzazz.deck+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["zaz"]
+  },
+  "application/voicexml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["vxml"]
+  },
+  "application/voucher-cms+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/vq-rtcpxr": {
+    "source": "iana"
+  },
+  "application/wasm": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["wasm"]
+  },
+  "application/watcherinfo+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["wif"]
+  },
+  "application/webpush-options+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/whoispp-query": {
+    "source": "iana"
+  },
+  "application/whoispp-response": {
+    "source": "iana"
+  },
+  "application/widget": {
+    "source": "iana",
+    "extensions": ["wgt"]
+  },
+  "application/winhlp": {
+    "source": "apache",
+    "extensions": ["hlp"]
+  },
+  "application/wita": {
+    "source": "iana"
+  },
+  "application/wordperfect5.1": {
+    "source": "iana"
+  },
+  "application/wsdl+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["wsdl"]
+  },
+  "application/wspolicy+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["wspolicy"]
+  },
+  "application/x-7z-compressed": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["7z"]
+  },
+  "application/x-abiword": {
+    "source": "apache",
+    "extensions": ["abw"]
+  },
+  "application/x-ace-compressed": {
+    "source": "apache",
+    "extensions": ["ace"]
+  },
+  "application/x-amf": {
+    "source": "apache"
+  },
+  "application/x-apple-diskimage": {
+    "source": "apache",
+    "extensions": ["dmg"]
+  },
+  "application/x-arj": {
+    "compressible": false,
+    "extensions": ["arj"]
+  },
+  "application/x-authorware-bin": {
+    "source": "apache",
+    "extensions": ["aab","x32","u32","vox"]
+  },
+  "application/x-authorware-map": {
+    "source": "apache",
+    "extensions": ["aam"]
+  },
+  "application/x-authorware-seg": {
+    "source": "apache",
+    "extensions": ["aas"]
+  },
+  "application/x-bcpio": {
+    "source": "apache",
+    "extensions": ["bcpio"]
+  },
+  "application/x-bdoc": {
+    "compressible": false,
+    "extensions": ["bdoc"]
+  },
+  "application/x-bittorrent": {
+    "source": "apache",
+    "extensions": ["torrent"]
+  },
+  "application/x-blorb": {
+    "source": "apache",
+    "extensions": ["blb","blorb"]
+  },
+  "application/x-bzip": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["bz"]
+  },
+  "application/x-bzip2": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["bz2","boz"]
+  },
+  "application/x-cbr": {
+    "source": "apache",
+    "extensions": ["cbr","cba","cbt","cbz","cb7"]
+  },
+  "application/x-cdlink": {
+    "source": "apache",
+    "extensions": ["vcd"]
+  },
+  "application/x-cfs-compressed": {
+    "source": "apache",
+    "extensions": ["cfs"]
+  },
+  "application/x-chat": {
+    "source": "apache",
+    "extensions": ["chat"]
+  },
+  "application/x-chess-pgn": {
+    "source": "apache",
+    "extensions": ["pgn"]
+  },
+  "application/x-chrome-extension": {
+    "extensions": ["crx"]
+  },
+  "application/x-cocoa": {
+    "source": "nginx",
+    "extensions": ["cco"]
+  },
+  "application/x-compress": {
+    "source": "apache"
+  },
+  "application/x-conference": {
+    "source": "apache",
+    "extensions": ["nsc"]
+  },
+  "application/x-cpio": {
+    "source": "apache",
+    "extensions": ["cpio"]
+  },
+  "application/x-csh": {
+    "source": "apache",
+    "extensions": ["csh"]
+  },
+  "application/x-deb": {
+    "compressible": false
+  },
+  "application/x-debian-package": {
+    "source": "apache",
+    "extensions": ["deb","udeb"]
+  },
+  "application/x-dgc-compressed": {
+    "source": "apache",
+    "extensions": ["dgc"]
+  },
+  "application/x-director": {
+    "source": "apache",
+    "extensions": ["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]
+  },
+  "application/x-doom": {
+    "source": "apache",
+    "extensions": ["wad"]
+  },
+  "application/x-dtbncx+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["ncx"]
+  },
+  "application/x-dtbook+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["dtb"]
+  },
+  "application/x-dtbresource+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["res"]
+  },
+  "application/x-dvi": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["dvi"]
+  },
+  "application/x-envoy": {
+    "source": "apache",
+    "extensions": ["evy"]
+  },
+  "application/x-eva": {
+    "source": "apache",
+    "extensions": ["eva"]
+  },
+  "application/x-font-bdf": {
+    "source": "apache",
+    "extensions": ["bdf"]
+  },
+  "application/x-font-dos": {
+    "source": "apache"
+  },
+  "application/x-font-framemaker": {
+    "source": "apache"
+  },
+  "application/x-font-ghostscript": {
+    "source": "apache",
+    "extensions": ["gsf"]
+  },
+  "application/x-font-libgrx": {
+    "source": "apache"
+  },
+  "application/x-font-linux-psf": {
+    "source": "apache",
+    "extensions": ["psf"]
+  },
+  "application/x-font-pcf": {
+    "source": "apache",
+    "extensions": ["pcf"]
+  },
+  "application/x-font-snf": {
+    "source": "apache",
+    "extensions": ["snf"]
+  },
+  "application/x-font-speedo": {
+    "source": "apache"
+  },
+  "application/x-font-sunos-news": {
+    "source": "apache"
+  },
+  "application/x-font-type1": {
+    "source": "apache",
+    "extensions": ["pfa","pfb","pfm","afm"]
+  },
+  "application/x-font-vfont": {
+    "source": "apache"
+  },
+  "application/x-freearc": {
+    "source": "apache",
+    "extensions": ["arc"]
+  },
+  "application/x-futuresplash": {
+    "source": "apache",
+    "extensions": ["spl"]
+  },
+  "application/x-gca-compressed": {
+    "source": "apache",
+    "extensions": ["gca"]
+  },
+  "application/x-glulx": {
+    "source": "apache",
+    "extensions": ["ulx"]
+  },
+  "application/x-gnumeric": {
+    "source": "apache",
+    "extensions": ["gnumeric"]
+  },
+  "application/x-gramps-xml": {
+    "source": "apache",
+    "extensions": ["gramps"]
+  },
+  "application/x-gtar": {
+    "source": "apache",
+    "extensions": ["gtar"]
+  },
+  "application/x-gzip": {
+    "source": "apache"
+  },
+  "application/x-hdf": {
+    "source": "apache",
+    "extensions": ["hdf"]
+  },
+  "application/x-httpd-php": {
+    "compressible": true,
+    "extensions": ["php"]
+  },
+  "application/x-install-instructions": {
+    "source": "apache",
+    "extensions": ["install"]
+  },
+  "application/x-iso9660-image": {
+    "source": "apache",
+    "extensions": ["iso"]
+  },
+  "application/x-iwork-keynote-sffkey": {
+    "extensions": ["key"]
+  },
+  "application/x-iwork-numbers-sffnumbers": {
+    "extensions": ["numbers"]
+  },
+  "application/x-iwork-pages-sffpages": {
+    "extensions": ["pages"]
+  },
+  "application/x-java-archive-diff": {
+    "source": "nginx",
+    "extensions": ["jardiff"]
+  },
+  "application/x-java-jnlp-file": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["jnlp"]
+  },
+  "application/x-javascript": {
+    "compressible": true
+  },
+  "application/x-keepass2": {
+    "extensions": ["kdbx"]
+  },
+  "application/x-latex": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["latex"]
+  },
+  "application/x-lua-bytecode": {
+    "extensions": ["luac"]
+  },
+  "application/x-lzh-compressed": {
+    "source": "apache",
+    "extensions": ["lzh","lha"]
+  },
+  "application/x-makeself": {
+    "source": "nginx",
+    "extensions": ["run"]
+  },
+  "application/x-mie": {
+    "source": "apache",
+    "extensions": ["mie"]
+  },
+  "application/x-mobipocket-ebook": {
+    "source": "apache",
+    "extensions": ["prc","mobi"]
+  },
+  "application/x-mpegurl": {
+    "compressible": false
+  },
+  "application/x-ms-application": {
+    "source": "apache",
+    "extensions": ["application"]
+  },
+  "application/x-ms-shortcut": {
+    "source": "apache",
+    "extensions": ["lnk"]
+  },
+  "application/x-ms-wmd": {
+    "source": "apache",
+    "extensions": ["wmd"]
+  },
+  "application/x-ms-wmz": {
+    "source": "apache",
+    "extensions": ["wmz"]
+  },
+  "application/x-ms-xbap": {
+    "source": "apache",
+    "extensions": ["xbap"]
+  },
+  "application/x-msaccess": {
+    "source": "apache",
+    "extensions": ["mdb"]
+  },
+  "application/x-msbinder": {
+    "source": "apache",
+    "extensions": ["obd"]
+  },
+  "application/x-mscardfile": {
+    "source": "apache",
+    "extensions": ["crd"]
+  },
+  "application/x-msclip": {
+    "source": "apache",
+    "extensions": ["clp"]
+  },
+  "application/x-msdos-program": {
+    "extensions": ["exe"]
+  },
+  "application/x-msdownload": {
+    "source": "apache",
+    "extensions": ["exe","dll","com","bat","msi"]
+  },
+  "application/x-msmediaview": {
+    "source": "apache",
+    "extensions": ["mvb","m13","m14"]
+  },
+  "application/x-msmetafile": {
+    "source": "apache",
+    "extensions": ["wmf","wmz","emf","emz"]
+  },
+  "application/x-msmoney": {
+    "source": "apache",
+    "extensions": ["mny"]
+  },
+  "application/x-mspublisher": {
+    "source": "apache",
+    "extensions": ["pub"]
+  },
+  "application/x-msschedule": {
+    "source": "apache",
+    "extensions": ["scd"]
+  },
+  "application/x-msterminal": {
+    "source": "apache",
+    "extensions": ["trm"]
+  },
+  "application/x-mswrite": {
+    "source": "apache",
+    "extensions": ["wri"]
+  },
+  "application/x-netcdf": {
+    "source": "apache",
+    "extensions": ["nc","cdf"]
+  },
+  "application/x-ns-proxy-autoconfig": {
+    "compressible": true,
+    "extensions": ["pac"]
+  },
+  "application/x-nzb": {
+    "source": "apache",
+    "extensions": ["nzb"]
+  },
+  "application/x-perl": {
+    "source": "nginx",
+    "extensions": ["pl","pm"]
+  },
+  "application/x-pilot": {
+    "source": "nginx",
+    "extensions": ["prc","pdb"]
+  },
+  "application/x-pkcs12": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["p12","pfx"]
+  },
+  "application/x-pkcs7-certificates": {
+    "source": "apache",
+    "extensions": ["p7b","spc"]
+  },
+  "application/x-pkcs7-certreqresp": {
+    "source": "apache",
+    "extensions": ["p7r"]
+  },
+  "application/x-pki-message": {
+    "source": "iana"
+  },
+  "application/x-rar-compressed": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["rar"]
+  },
+  "application/x-redhat-package-manager": {
+    "source": "nginx",
+    "extensions": ["rpm"]
+  },
+  "application/x-research-info-systems": {
+    "source": "apache",
+    "extensions": ["ris"]
+  },
+  "application/x-sea": {
+    "source": "nginx",
+    "extensions": ["sea"]
+  },
+  "application/x-sh": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["sh"]
+  },
+  "application/x-shar": {
+    "source": "apache",
+    "extensions": ["shar"]
+  },
+  "application/x-shockwave-flash": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["swf"]
+  },
+  "application/x-silverlight-app": {
+    "source": "apache",
+    "extensions": ["xap"]
+  },
+  "application/x-sql": {
+    "source": "apache",
+    "extensions": ["sql"]
+  },
+  "application/x-stuffit": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["sit"]
+  },
+  "application/x-stuffitx": {
+    "source": "apache",
+    "extensions": ["sitx"]
+  },
+  "application/x-subrip": {
+    "source": "apache",
+    "extensions": ["srt"]
+  },
+  "application/x-sv4cpio": {
+    "source": "apache",
+    "extensions": ["sv4cpio"]
+  },
+  "application/x-sv4crc": {
+    "source": "apache",
+    "extensions": ["sv4crc"]
+  },
+  "application/x-t3vm-image": {
+    "source": "apache",
+    "extensions": ["t3"]
+  },
+  "application/x-tads": {
+    "source": "apache",
+    "extensions": ["gam"]
+  },
+  "application/x-tar": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["tar"]
+  },
+  "application/x-tcl": {
+    "source": "apache",
+    "extensions": ["tcl","tk"]
+  },
+  "application/x-tex": {
+    "source": "apache",
+    "extensions": ["tex"]
+  },
+  "application/x-tex-tfm": {
+    "source": "apache",
+    "extensions": ["tfm"]
+  },
+  "application/x-texinfo": {
+    "source": "apache",
+    "extensions": ["texinfo","texi"]
+  },
+  "application/x-tgif": {
+    "source": "apache",
+    "extensions": ["obj"]
+  },
+  "application/x-ustar": {
+    "source": "apache",
+    "extensions": ["ustar"]
+  },
+  "application/x-virtualbox-hdd": {
+    "compressible": true,
+    "extensions": ["hdd"]
+  },
+  "application/x-virtualbox-ova": {
+    "compressible": true,
+    "extensions": ["ova"]
+  },
+  "application/x-virtualbox-ovf": {
+    "compressible": true,
+    "extensions": ["ovf"]
+  },
+  "application/x-virtualbox-vbox": {
+    "compressible": true,
+    "extensions": ["vbox"]
+  },
+  "application/x-virtualbox-vbox-extpack": {
+    "compressible": false,
+    "extensions": ["vbox-extpack"]
+  },
+  "application/x-virtualbox-vdi": {
+    "compressible": true,
+    "extensions": ["vdi"]
+  },
+  "application/x-virtualbox-vhd": {
+    "compressible": true,
+    "extensions": ["vhd"]
+  },
+  "application/x-virtualbox-vmdk": {
+    "compressible": true,
+    "extensions": ["vmdk"]
+  },
+  "application/x-wais-source": {
+    "source": "apache",
+    "extensions": ["src"]
+  },
+  "application/x-web-app-manifest+json": {
+    "compressible": true,
+    "extensions": ["webapp"]
+  },
+  "application/x-www-form-urlencoded": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/x-x509-ca-cert": {
+    "source": "iana",
+    "extensions": ["der","crt","pem"]
+  },
+  "application/x-x509-ca-ra-cert": {
+    "source": "iana"
+  },
+  "application/x-x509-next-ca-cert": {
+    "source": "iana"
+  },
+  "application/x-xfig": {
+    "source": "apache",
+    "extensions": ["fig"]
+  },
+  "application/x-xliff+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["xlf"]
+  },
+  "application/x-xpinstall": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["xpi"]
+  },
+  "application/x-xz": {
+    "source": "apache",
+    "extensions": ["xz"]
+  },
+  "application/x-zmachine": {
+    "source": "apache",
+    "extensions": ["z1","z2","z3","z4","z5","z6","z7","z8"]
+  },
+  "application/x400-bp": {
+    "source": "iana"
+  },
+  "application/xacml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/xaml+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["xaml"]
+  },
+  "application/xcap-att+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xav"]
+  },
+  "application/xcap-caps+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xca"]
+  },
+  "application/xcap-diff+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xdf"]
+  },
+  "application/xcap-el+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xel"]
+  },
+  "application/xcap-error+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/xcap-ns+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xns"]
+  },
+  "application/xcon-conference-info+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/xcon-conference-info-diff+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/xenc+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xenc"]
+  },
+  "application/xhtml+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xhtml","xht"]
+  },
+  "application/xhtml-voice+xml": {
+    "source": "apache",
+    "compressible": true
+  },
+  "application/xliff+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xlf"]
+  },
+  "application/xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xml","xsl","xsd","rng"]
+  },
+  "application/xml-dtd": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["dtd"]
+  },
+  "application/xml-external-parsed-entity": {
+    "source": "iana"
+  },
+  "application/xml-patch+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/xmpp+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/xop+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xop"]
+  },
+  "application/xproc+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["xpl"]
+  },
+  "application/xslt+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xsl","xslt"]
+  },
+  "application/xspf+xml": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["xspf"]
+  },
+  "application/xv+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["mxml","xhvml","xvml","xvm"]
+  },
+  "application/yang": {
+    "source": "iana",
+    "extensions": ["yang"]
+  },
+  "application/yang-data+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/yang-data+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/yang-patch+json": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/yang-patch+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "application/yin+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["yin"]
+  },
+  "application/zip": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["zip"]
+  },
+  "application/zlib": {
+    "source": "iana"
+  },
+  "application/zstd": {
+    "source": "iana"
+  },
+  "audio/1d-interleaved-parityfec": {
+    "source": "iana"
+  },
+  "audio/32kadpcm": {
+    "source": "iana"
+  },
+  "audio/3gpp": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["3gpp"]
+  },
+  "audio/3gpp2": {
+    "source": "iana"
+  },
+  "audio/aac": {
+    "source": "iana"
+  },
+  "audio/ac3": {
+    "source": "iana"
+  },
+  "audio/adpcm": {
+    "source": "apache",
+    "extensions": ["adp"]
+  },
+  "audio/amr": {
+    "source": "iana",
+    "extensions": ["amr"]
+  },
+  "audio/amr-wb": {
+    "source": "iana"
+  },
+  "audio/amr-wb+": {
+    "source": "iana"
+  },
+  "audio/aptx": {
+    "source": "iana"
+  },
+  "audio/asc": {
+    "source": "iana"
+  },
+  "audio/atrac-advanced-lossless": {
+    "source": "iana"
+  },
+  "audio/atrac-x": {
+    "source": "iana"
+  },
+  "audio/atrac3": {
+    "source": "iana"
+  },
+  "audio/basic": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["au","snd"]
+  },
+  "audio/bv16": {
+    "source": "iana"
+  },
+  "audio/bv32": {
+    "source": "iana"
+  },
+  "audio/clearmode": {
+    "source": "iana"
+  },
+  "audio/cn": {
+    "source": "iana"
+  },
+  "audio/dat12": {
+    "source": "iana"
+  },
+  "audio/dls": {
+    "source": "iana"
+  },
+  "audio/dsr-es201108": {
+    "source": "iana"
+  },
+  "audio/dsr-es202050": {
+    "source": "iana"
+  },
+  "audio/dsr-es202211": {
+    "source": "iana"
+  },
+  "audio/dsr-es202212": {
+    "source": "iana"
+  },
+  "audio/dv": {
+    "source": "iana"
+  },
+  "audio/dvi4": {
+    "source": "iana"
+  },
+  "audio/eac3": {
+    "source": "iana"
+  },
+  "audio/encaprtp": {
+    "source": "iana"
+  },
+  "audio/evrc": {
+    "source": "iana"
+  },
+  "audio/evrc-qcp": {
+    "source": "iana"
+  },
+  "audio/evrc0": {
+    "source": "iana"
+  },
+  "audio/evrc1": {
+    "source": "iana"
+  },
+  "audio/evrcb": {
+    "source": "iana"
+  },
+  "audio/evrcb0": {
+    "source": "iana"
+  },
+  "audio/evrcb1": {
+    "source": "iana"
+  },
+  "audio/evrcnw": {
+    "source": "iana"
+  },
+  "audio/evrcnw0": {
+    "source": "iana"
+  },
+  "audio/evrcnw1": {
+    "source": "iana"
+  },
+  "audio/evrcwb": {
+    "source": "iana"
+  },
+  "audio/evrcwb0": {
+    "source": "iana"
+  },
+  "audio/evrcwb1": {
+    "source": "iana"
+  },
+  "audio/evs": {
+    "source": "iana"
+  },
+  "audio/flexfec": {
+    "source": "iana"
+  },
+  "audio/fwdred": {
+    "source": "iana"
+  },
+  "audio/g711-0": {
+    "source": "iana"
+  },
+  "audio/g719": {
+    "source": "iana"
+  },
+  "audio/g722": {
+    "source": "iana"
+  },
+  "audio/g7221": {
+    "source": "iana"
+  },
+  "audio/g723": {
+    "source": "iana"
+  },
+  "audio/g726-16": {
+    "source": "iana"
+  },
+  "audio/g726-24": {
+    "source": "iana"
+  },
+  "audio/g726-32": {
+    "source": "iana"
+  },
+  "audio/g726-40": {
+    "source": "iana"
+  },
+  "audio/g728": {
+    "source": "iana"
+  },
+  "audio/g729": {
+    "source": "iana"
+  },
+  "audio/g7291": {
+    "source": "iana"
+  },
+  "audio/g729d": {
+    "source": "iana"
+  },
+  "audio/g729e": {
+    "source": "iana"
+  },
+  "audio/gsm": {
+    "source": "iana"
+  },
+  "audio/gsm-efr": {
+    "source": "iana"
+  },
+  "audio/gsm-hr-08": {
+    "source": "iana"
+  },
+  "audio/ilbc": {
+    "source": "iana"
+  },
+  "audio/ip-mr_v2.5": {
+    "source": "iana"
+  },
+  "audio/isac": {
+    "source": "apache"
+  },
+  "audio/l16": {
+    "source": "iana"
+  },
+  "audio/l20": {
+    "source": "iana"
+  },
+  "audio/l24": {
+    "source": "iana",
+    "compressible": false
+  },
+  "audio/l8": {
+    "source": "iana"
+  },
+  "audio/lpc": {
+    "source": "iana"
+  },
+  "audio/melp": {
+    "source": "iana"
+  },
+  "audio/melp1200": {
+    "source": "iana"
+  },
+  "audio/melp2400": {
+    "source": "iana"
+  },
+  "audio/melp600": {
+    "source": "iana"
+  },
+  "audio/mhas": {
+    "source": "iana"
+  },
+  "audio/midi": {
+    "source": "apache",
+    "extensions": ["mid","midi","kar","rmi"]
+  },
+  "audio/mobile-xmf": {
+    "source": "iana",
+    "extensions": ["mxmf"]
+  },
+  "audio/mp3": {
+    "compressible": false,
+    "extensions": ["mp3"]
+  },
+  "audio/mp4": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["m4a","mp4a"]
+  },
+  "audio/mp4a-latm": {
+    "source": "iana"
+  },
+  "audio/mpa": {
+    "source": "iana"
+  },
+  "audio/mpa-robust": {
+    "source": "iana"
+  },
+  "audio/mpeg": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["mpga","mp2","mp2a","mp3","m2a","m3a"]
+  },
+  "audio/mpeg4-generic": {
+    "source": "iana"
+  },
+  "audio/musepack": {
+    "source": "apache"
+  },
+  "audio/ogg": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["oga","ogg","spx","opus"]
+  },
+  "audio/opus": {
+    "source": "iana"
+  },
+  "audio/parityfec": {
+    "source": "iana"
+  },
+  "audio/pcma": {
+    "source": "iana"
+  },
+  "audio/pcma-wb": {
+    "source": "iana"
+  },
+  "audio/pcmu": {
+    "source": "iana"
+  },
+  "audio/pcmu-wb": {
+    "source": "iana"
+  },
+  "audio/prs.sid": {
+    "source": "iana"
+  },
+  "audio/qcelp": {
+    "source": "iana"
+  },
+  "audio/raptorfec": {
+    "source": "iana"
+  },
+  "audio/red": {
+    "source": "iana"
+  },
+  "audio/rtp-enc-aescm128": {
+    "source": "iana"
+  },
+  "audio/rtp-midi": {
+    "source": "iana"
+  },
+  "audio/rtploopback": {
+    "source": "iana"
+  },
+  "audio/rtx": {
+    "source": "iana"
+  },
+  "audio/s3m": {
+    "source": "apache",
+    "extensions": ["s3m"]
+  },
+  "audio/scip": {
+    "source": "iana"
+  },
+  "audio/silk": {
+    "source": "apache",
+    "extensions": ["sil"]
+  },
+  "audio/smv": {
+    "source": "iana"
+  },
+  "audio/smv-qcp": {
+    "source": "iana"
+  },
+  "audio/smv0": {
+    "source": "iana"
+  },
+  "audio/sofa": {
+    "source": "iana"
+  },
+  "audio/sp-midi": {
+    "source": "iana"
+  },
+  "audio/speex": {
+    "source": "iana"
+  },
+  "audio/t140c": {
+    "source": "iana"
+  },
+  "audio/t38": {
+    "source": "iana"
+  },
+  "audio/telephone-event": {
+    "source": "iana"
+  },
+  "audio/tetra_acelp": {
+    "source": "iana"
+  },
+  "audio/tetra_acelp_bb": {
+    "source": "iana"
+  },
+  "audio/tone": {
+    "source": "iana"
+  },
+  "audio/tsvcis": {
+    "source": "iana"
+  },
+  "audio/uemclip": {
+    "source": "iana"
+  },
+  "audio/ulpfec": {
+    "source": "iana"
+  },
+  "audio/usac": {
+    "source": "iana"
+  },
+  "audio/vdvi": {
+    "source": "iana"
+  },
+  "audio/vmr-wb": {
+    "source": "iana"
+  },
+  "audio/vnd.3gpp.iufp": {
+    "source": "iana"
+  },
+  "audio/vnd.4sb": {
+    "source": "iana"
+  },
+  "audio/vnd.audiokoz": {
+    "source": "iana"
+  },
+  "audio/vnd.celp": {
+    "source": "iana"
+  },
+  "audio/vnd.cisco.nse": {
+    "source": "iana"
+  },
+  "audio/vnd.cmles.radio-events": {
+    "source": "iana"
+  },
+  "audio/vnd.cns.anp1": {
+    "source": "iana"
+  },
+  "audio/vnd.cns.inf1": {
+    "source": "iana"
+  },
+  "audio/vnd.dece.audio": {
+    "source": "iana",
+    "extensions": ["uva","uvva"]
+  },
+  "audio/vnd.digital-winds": {
+    "source": "iana",
+    "extensions": ["eol"]
+  },
+  "audio/vnd.dlna.adts": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.heaac.1": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.heaac.2": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.mlp": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.mps": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.pl2": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.pl2x": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.pl2z": {
+    "source": "iana"
+  },
+  "audio/vnd.dolby.pulse.1": {
+    "source": "iana"
+  },
+  "audio/vnd.dra": {
+    "source": "iana",
+    "extensions": ["dra"]
+  },
+  "audio/vnd.dts": {
+    "source": "iana",
+    "extensions": ["dts"]
+  },
+  "audio/vnd.dts.hd": {
+    "source": "iana",
+    "extensions": ["dtshd"]
+  },
+  "audio/vnd.dts.uhd": {
+    "source": "iana"
+  },
+  "audio/vnd.dvb.file": {
+    "source": "iana"
+  },
+  "audio/vnd.everad.plj": {
+    "source": "iana"
+  },
+  "audio/vnd.hns.audio": {
+    "source": "iana"
+  },
+  "audio/vnd.lucent.voice": {
+    "source": "iana",
+    "extensions": ["lvp"]
+  },
+  "audio/vnd.ms-playready.media.pya": {
+    "source": "iana",
+    "extensions": ["pya"]
+  },
+  "audio/vnd.nokia.mobile-xmf": {
+    "source": "iana"
+  },
+  "audio/vnd.nortel.vbk": {
+    "source": "iana"
+  },
+  "audio/vnd.nuera.ecelp4800": {
+    "source": "iana",
+    "extensions": ["ecelp4800"]
+  },
+  "audio/vnd.nuera.ecelp7470": {
+    "source": "iana",
+    "extensions": ["ecelp7470"]
+  },
+  "audio/vnd.nuera.ecelp9600": {
+    "source": "iana",
+    "extensions": ["ecelp9600"]
+  },
+  "audio/vnd.octel.sbc": {
+    "source": "iana"
+  },
+  "audio/vnd.presonus.multitrack": {
+    "source": "iana"
+  },
+  "audio/vnd.qcelp": {
+    "source": "iana"
+  },
+  "audio/vnd.rhetorex.32kadpcm": {
+    "source": "iana"
+  },
+  "audio/vnd.rip": {
+    "source": "iana",
+    "extensions": ["rip"]
+  },
+  "audio/vnd.rn-realaudio": {
+    "compressible": false
+  },
+  "audio/vnd.sealedmedia.softseal.mpeg": {
+    "source": "iana"
+  },
+  "audio/vnd.vmx.cvsd": {
+    "source": "iana"
+  },
+  "audio/vnd.wave": {
+    "compressible": false
+  },
+  "audio/vorbis": {
+    "source": "iana",
+    "compressible": false
+  },
+  "audio/vorbis-config": {
+    "source": "iana"
+  },
+  "audio/wav": {
+    "compressible": false,
+    "extensions": ["wav"]
+  },
+  "audio/wave": {
+    "compressible": false,
+    "extensions": ["wav"]
+  },
+  "audio/webm": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["weba"]
+  },
+  "audio/x-aac": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["aac"]
+  },
+  "audio/x-aiff": {
+    "source": "apache",
+    "extensions": ["aif","aiff","aifc"]
+  },
+  "audio/x-caf": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["caf"]
+  },
+  "audio/x-flac": {
+    "source": "apache",
+    "extensions": ["flac"]
+  },
+  "audio/x-m4a": {
+    "source": "nginx",
+    "extensions": ["m4a"]
+  },
+  "audio/x-matroska": {
+    "source": "apache",
+    "extensions": ["mka"]
+  },
+  "audio/x-mpegurl": {
+    "source": "apache",
+    "extensions": ["m3u"]
+  },
+  "audio/x-ms-wax": {
+    "source": "apache",
+    "extensions": ["wax"]
+  },
+  "audio/x-ms-wma": {
+    "source": "apache",
+    "extensions": ["wma"]
+  },
+  "audio/x-pn-realaudio": {
+    "source": "apache",
+    "extensions": ["ram","ra"]
+  },
+  "audio/x-pn-realaudio-plugin": {
+    "source": "apache",
+    "extensions": ["rmp"]
+  },
+  "audio/x-realaudio": {
+    "source": "nginx",
+    "extensions": ["ra"]
+  },
+  "audio/x-tta": {
+    "source": "apache"
+  },
+  "audio/x-wav": {
+    "source": "apache",
+    "extensions": ["wav"]
+  },
+  "audio/xm": {
+    "source": "apache",
+    "extensions": ["xm"]
+  },
+  "chemical/x-cdx": {
+    "source": "apache",
+    "extensions": ["cdx"]
+  },
+  "chemical/x-cif": {
+    "source": "apache",
+    "extensions": ["cif"]
+  },
+  "chemical/x-cmdf": {
+    "source": "apache",
+    "extensions": ["cmdf"]
+  },
+  "chemical/x-cml": {
+    "source": "apache",
+    "extensions": ["cml"]
+  },
+  "chemical/x-csml": {
+    "source": "apache",
+    "extensions": ["csml"]
+  },
+  "chemical/x-pdb": {
+    "source": "apache"
+  },
+  "chemical/x-xyz": {
+    "source": "apache",
+    "extensions": ["xyz"]
+  },
+  "font/collection": {
+    "source": "iana",
+    "extensions": ["ttc"]
+  },
+  "font/otf": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["otf"]
+  },
+  "font/sfnt": {
+    "source": "iana"
+  },
+  "font/ttf": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ttf"]
+  },
+  "font/woff": {
+    "source": "iana",
+    "extensions": ["woff"]
+  },
+  "font/woff2": {
+    "source": "iana",
+    "extensions": ["woff2"]
+  },
+  "image/aces": {
+    "source": "iana",
+    "extensions": ["exr"]
+  },
+  "image/apng": {
+    "compressible": false,
+    "extensions": ["apng"]
+  },
+  "image/avci": {
+    "source": "iana",
+    "extensions": ["avci"]
+  },
+  "image/avcs": {
+    "source": "iana",
+    "extensions": ["avcs"]
+  },
+  "image/avif": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["avif"]
+  },
+  "image/bmp": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["bmp"]
+  },
+  "image/cgm": {
+    "source": "iana",
+    "extensions": ["cgm"]
+  },
+  "image/dicom-rle": {
+    "source": "iana",
+    "extensions": ["drle"]
+  },
+  "image/emf": {
+    "source": "iana",
+    "extensions": ["emf"]
+  },
+  "image/fits": {
+    "source": "iana",
+    "extensions": ["fits"]
+  },
+  "image/g3fax": {
+    "source": "iana",
+    "extensions": ["g3"]
+  },
+  "image/gif": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["gif"]
+  },
+  "image/heic": {
+    "source": "iana",
+    "extensions": ["heic"]
+  },
+  "image/heic-sequence": {
+    "source": "iana",
+    "extensions": ["heics"]
+  },
+  "image/heif": {
+    "source": "iana",
+    "extensions": ["heif"]
+  },
+  "image/heif-sequence": {
+    "source": "iana",
+    "extensions": ["heifs"]
+  },
+  "image/hej2k": {
+    "source": "iana",
+    "extensions": ["hej2"]
+  },
+  "image/hsj2": {
+    "source": "iana",
+    "extensions": ["hsj2"]
+  },
+  "image/ief": {
+    "source": "iana",
+    "extensions": ["ief"]
+  },
+  "image/jls": {
+    "source": "iana",
+    "extensions": ["jls"]
+  },
+  "image/jp2": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["jp2","jpg2"]
+  },
+  "image/jpeg": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["jpeg","jpg","jpe"]
+  },
+  "image/jph": {
+    "source": "iana",
+    "extensions": ["jph"]
+  },
+  "image/jphc": {
+    "source": "iana",
+    "extensions": ["jhc"]
+  },
+  "image/jpm": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["jpm"]
+  },
+  "image/jpx": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["jpx","jpf"]
+  },
+  "image/jxr": {
+    "source": "iana",
+    "extensions": ["jxr"]
+  },
+  "image/jxra": {
+    "source": "iana",
+    "extensions": ["jxra"]
+  },
+  "image/jxrs": {
+    "source": "iana",
+    "extensions": ["jxrs"]
+  },
+  "image/jxs": {
+    "source": "iana",
+    "extensions": ["jxs"]
+  },
+  "image/jxsc": {
+    "source": "iana",
+    "extensions": ["jxsc"]
+  },
+  "image/jxsi": {
+    "source": "iana",
+    "extensions": ["jxsi"]
+  },
+  "image/jxss": {
+    "source": "iana",
+    "extensions": ["jxss"]
+  },
+  "image/ktx": {
+    "source": "iana",
+    "extensions": ["ktx"]
+  },
+  "image/ktx2": {
+    "source": "iana",
+    "extensions": ["ktx2"]
+  },
+  "image/naplps": {
+    "source": "iana"
+  },
+  "image/pjpeg": {
+    "compressible": false
+  },
+  "image/png": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["png"]
+  },
+  "image/prs.btif": {
+    "source": "iana",
+    "extensions": ["btif"]
+  },
+  "image/prs.pti": {
+    "source": "iana",
+    "extensions": ["pti"]
+  },
+  "image/pwg-raster": {
+    "source": "iana"
+  },
+  "image/sgi": {
+    "source": "apache",
+    "extensions": ["sgi"]
+  },
+  "image/svg+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["svg","svgz"]
+  },
+  "image/t38": {
+    "source": "iana",
+    "extensions": ["t38"]
+  },
+  "image/tiff": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["tif","tiff"]
+  },
+  "image/tiff-fx": {
+    "source": "iana",
+    "extensions": ["tfx"]
+  },
+  "image/vnd.adobe.photoshop": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["psd"]
+  },
+  "image/vnd.airzip.accelerator.azv": {
+    "source": "iana",
+    "extensions": ["azv"]
+  },
+  "image/vnd.cns.inf2": {
+    "source": "iana"
+  },
+  "image/vnd.dece.graphic": {
+    "source": "iana",
+    "extensions": ["uvi","uvvi","uvg","uvvg"]
+  },
+  "image/vnd.djvu": {
+    "source": "iana",
+    "extensions": ["djvu","djv"]
+  },
+  "image/vnd.dvb.subtitle": {
+    "source": "iana",
+    "extensions": ["sub"]
+  },
+  "image/vnd.dwg": {
+    "source": "iana",
+    "extensions": ["dwg"]
+  },
+  "image/vnd.dxf": {
+    "source": "iana",
+    "extensions": ["dxf"]
+  },
+  "image/vnd.fastbidsheet": {
+    "source": "iana",
+    "extensions": ["fbs"]
+  },
+  "image/vnd.fpx": {
+    "source": "iana",
+    "extensions": ["fpx"]
+  },
+  "image/vnd.fst": {
+    "source": "iana",
+    "extensions": ["fst"]
+  },
+  "image/vnd.fujixerox.edmics-mmr": {
+    "source": "iana",
+    "extensions": ["mmr"]
+  },
+  "image/vnd.fujixerox.edmics-rlc": {
+    "source": "iana",
+    "extensions": ["rlc"]
+  },
+  "image/vnd.globalgraphics.pgb": {
+    "source": "iana"
+  },
+  "image/vnd.microsoft.icon": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["ico"]
+  },
+  "image/vnd.mix": {
+    "source": "iana"
+  },
+  "image/vnd.mozilla.apng": {
+    "source": "iana"
+  },
+  "image/vnd.ms-dds": {
+    "compressible": true,
+    "extensions": ["dds"]
+  },
+  "image/vnd.ms-modi": {
+    "source": "iana",
+    "extensions": ["mdi"]
+  },
+  "image/vnd.ms-photo": {
+    "source": "apache",
+    "extensions": ["wdp"]
+  },
+  "image/vnd.net-fpx": {
+    "source": "iana",
+    "extensions": ["npx"]
+  },
+  "image/vnd.pco.b16": {
+    "source": "iana",
+    "extensions": ["b16"]
+  },
+  "image/vnd.radiance": {
+    "source": "iana"
+  },
+  "image/vnd.sealed.png": {
+    "source": "iana"
+  },
+  "image/vnd.sealedmedia.softseal.gif": {
+    "source": "iana"
+  },
+  "image/vnd.sealedmedia.softseal.jpg": {
+    "source": "iana"
+  },
+  "image/vnd.svf": {
+    "source": "iana"
+  },
+  "image/vnd.tencent.tap": {
+    "source": "iana",
+    "extensions": ["tap"]
+  },
+  "image/vnd.valve.source.texture": {
+    "source": "iana",
+    "extensions": ["vtf"]
+  },
+  "image/vnd.wap.wbmp": {
+    "source": "iana",
+    "extensions": ["wbmp"]
+  },
+  "image/vnd.xiff": {
+    "source": "iana",
+    "extensions": ["xif"]
+  },
+  "image/vnd.zbrush.pcx": {
+    "source": "iana",
+    "extensions": ["pcx"]
+  },
+  "image/webp": {
+    "source": "apache",
+    "extensions": ["webp"]
+  },
+  "image/wmf": {
+    "source": "iana",
+    "extensions": ["wmf"]
+  },
+  "image/x-3ds": {
+    "source": "apache",
+    "extensions": ["3ds"]
+  },
+  "image/x-cmu-raster": {
+    "source": "apache",
+    "extensions": ["ras"]
+  },
+  "image/x-cmx": {
+    "source": "apache",
+    "extensions": ["cmx"]
+  },
+  "image/x-freehand": {
+    "source": "apache",
+    "extensions": ["fh","fhc","fh4","fh5","fh7"]
+  },
+  "image/x-icon": {
+    "source": "apache",
+    "compressible": true,
+    "extensions": ["ico"]
+  },
+  "image/x-jng": {
+    "source": "nginx",
+    "extensions": ["jng"]
+  },
+  "image/x-mrsid-image": {
+    "source": "apache",
+    "extensions": ["sid"]
+  },
+  "image/x-ms-bmp": {
+    "source": "nginx",
+    "compressible": true,
+    "extensions": ["bmp"]
+  },
+  "image/x-pcx": {
+    "source": "apache",
+    "extensions": ["pcx"]
+  },
+  "image/x-pict": {
+    "source": "apache",
+    "extensions": ["pic","pct"]
+  },
+  "image/x-portable-anymap": {
+    "source": "apache",
+    "extensions": ["pnm"]
+  },
+  "image/x-portable-bitmap": {
+    "source": "apache",
+    "extensions": ["pbm"]
+  },
+  "image/x-portable-graymap": {
+    "source": "apache",
+    "extensions": ["pgm"]
+  },
+  "image/x-portable-pixmap": {
+    "source": "apache",
+    "extensions": ["ppm"]
+  },
+  "image/x-rgb": {
+    "source": "apache",
+    "extensions": ["rgb"]
+  },
+  "image/x-tga": {
+    "source": "apache",
+    "extensions": ["tga"]
+  },
+  "image/x-xbitmap": {
+    "source": "apache",
+    "extensions": ["xbm"]
+  },
+  "image/x-xcf": {
+    "compressible": false
+  },
+  "image/x-xpixmap": {
+    "source": "apache",
+    "extensions": ["xpm"]
+  },
+  "image/x-xwindowdump": {
+    "source": "apache",
+    "extensions": ["xwd"]
+  },
+  "message/cpim": {
+    "source": "iana"
+  },
+  "message/delivery-status": {
+    "source": "iana"
+  },
+  "message/disposition-notification": {
+    "source": "iana",
+    "extensions": [
+      "disposition-notification"
+    ]
+  },
+  "message/external-body": {
+    "source": "iana"
+  },
+  "message/feedback-report": {
+    "source": "iana"
+  },
+  "message/global": {
+    "source": "iana",
+    "extensions": ["u8msg"]
+  },
+  "message/global-delivery-status": {
+    "source": "iana",
+    "extensions": ["u8dsn"]
+  },
+  "message/global-disposition-notification": {
+    "source": "iana",
+    "extensions": ["u8mdn"]
+  },
+  "message/global-headers": {
+    "source": "iana",
+    "extensions": ["u8hdr"]
+  },
+  "message/http": {
+    "source": "iana",
+    "compressible": false
+  },
+  "message/imdn+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "message/news": {
+    "source": "iana"
+  },
+  "message/partial": {
+    "source": "iana",
+    "compressible": false
+  },
+  "message/rfc822": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["eml","mime"]
+  },
+  "message/s-http": {
+    "source": "iana"
+  },
+  "message/sip": {
+    "source": "iana"
+  },
+  "message/sipfrag": {
+    "source": "iana"
+  },
+  "message/tracking-status": {
+    "source": "iana"
+  },
+  "message/vnd.si.simp": {
+    "source": "iana"
+  },
+  "message/vnd.wfa.wsc": {
+    "source": "iana",
+    "extensions": ["wsc"]
+  },
+  "model/3mf": {
+    "source": "iana",
+    "extensions": ["3mf"]
+  },
+  "model/e57": {
+    "source": "iana"
+  },
+  "model/gltf+json": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["gltf"]
+  },
+  "model/gltf-binary": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["glb"]
+  },
+  "model/iges": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["igs","iges"]
+  },
+  "model/mesh": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["msh","mesh","silo"]
+  },
+  "model/mtl": {
+    "source": "iana",
+    "extensions": ["mtl"]
+  },
+  "model/obj": {
+    "source": "iana",
+    "extensions": ["obj"]
+  },
+  "model/step": {
+    "source": "iana"
+  },
+  "model/step+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["stpx"]
+  },
+  "model/step+zip": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["stpz"]
+  },
+  "model/step-xml+zip": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["stpxz"]
+  },
+  "model/stl": {
+    "source": "iana",
+    "extensions": ["stl"]
+  },
+  "model/vnd.collada+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["dae"]
+  },
+  "model/vnd.dwf": {
+    "source": "iana",
+    "extensions": ["dwf"]
+  },
+  "model/vnd.flatland.3dml": {
+    "source": "iana"
+  },
+  "model/vnd.gdl": {
+    "source": "iana",
+    "extensions": ["gdl"]
+  },
+  "model/vnd.gs-gdl": {
+    "source": "apache"
+  },
+  "model/vnd.gs.gdl": {
+    "source": "iana"
+  },
+  "model/vnd.gtw": {
+    "source": "iana",
+    "extensions": ["gtw"]
+  },
+  "model/vnd.moml+xml": {
+    "source": "iana",
+    "compressible": true
+  },
+  "model/vnd.mts": {
+    "source": "iana",
+    "extensions": ["mts"]
+  },
+  "model/vnd.opengex": {
+    "source": "iana",
+    "extensions": ["ogex"]
+  },
+  "model/vnd.parasolid.transmit.binary": {
+    "source": "iana",
+    "extensions": ["x_b"]
+  },
+  "model/vnd.parasolid.transmit.text": {
+    "source": "iana",
+    "extensions": ["x_t"]
+  },
+  "model/vnd.pytha.pyox": {
+    "source": "iana"
+  },
+  "model/vnd.rosette.annotated-data-model": {
+    "source": "iana"
+  },
+  "model/vnd.sap.vds": {
+    "source": "iana",
+    "extensions": ["vds"]
+  },
+  "model/vnd.usdz+zip": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["usdz"]
+  },
+  "model/vnd.valve.source.compiled-map": {
+    "source": "iana",
+    "extensions": ["bsp"]
+  },
+  "model/vnd.vtu": {
+    "source": "iana",
+    "extensions": ["vtu"]
+  },
+  "model/vrml": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["wrl","vrml"]
+  },
+  "model/x3d+binary": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["x3db","x3dbz"]
+  },
+  "model/x3d+fastinfoset": {
+    "source": "iana",
+    "extensions": ["x3db"]
+  },
+  "model/x3d+vrml": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["x3dv","x3dvz"]
+  },
+  "model/x3d+xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["x3d","x3dz"]
+  },
+  "model/x3d-vrml": {
+    "source": "iana",
+    "extensions": ["x3dv"]
+  },
+  "multipart/alternative": {
+    "source": "iana",
+    "compressible": false
+  },
+  "multipart/appledouble": {
+    "source": "iana"
+  },
+  "multipart/byteranges": {
+    "source": "iana"
+  },
+  "multipart/digest": {
+    "source": "iana"
+  },
+  "multipart/encrypted": {
+    "source": "iana",
+    "compressible": false
+  },
+  "multipart/form-data": {
+    "source": "iana",
+    "compressible": false
+  },
+  "multipart/header-set": {
+    "source": "iana"
+  },
+  "multipart/mixed": {
+    "source": "iana"
+  },
+  "multipart/multilingual": {
+    "source": "iana"
+  },
+  "multipart/parallel": {
+    "source": "iana"
+  },
+  "multipart/related": {
+    "source": "iana",
+    "compressible": false
+  },
+  "multipart/report": {
+    "source": "iana"
+  },
+  "multipart/signed": {
+    "source": "iana",
+    "compressible": false
+  },
+  "multipart/vnd.bint.med-plus": {
+    "source": "iana"
+  },
+  "multipart/voice-message": {
+    "source": "iana"
+  },
+  "multipart/x-mixed-replace": {
+    "source": "iana"
+  },
+  "text/1d-interleaved-parityfec": {
+    "source": "iana"
+  },
+  "text/cache-manifest": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["appcache","manifest"]
+  },
+  "text/calendar": {
+    "source": "iana",
+    "extensions": ["ics","ifb"]
+  },
+  "text/calender": {
+    "compressible": true
+  },
+  "text/cmd": {
+    "compressible": true
+  },
+  "text/coffeescript": {
+    "extensions": ["coffee","litcoffee"]
+  },
+  "text/cql": {
+    "source": "iana"
+  },
+  "text/cql-expression": {
+    "source": "iana"
+  },
+  "text/cql-identifier": {
+    "source": "iana"
+  },
+  "text/css": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["css"]
+  },
+  "text/csv": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["csv"]
+  },
+  "text/csv-schema": {
+    "source": "iana"
+  },
+  "text/directory": {
+    "source": "iana"
+  },
+  "text/dns": {
+    "source": "iana"
+  },
+  "text/ecmascript": {
+    "source": "iana"
+  },
+  "text/encaprtp": {
+    "source": "iana"
+  },
+  "text/enriched": {
+    "source": "iana"
+  },
+  "text/fhirpath": {
+    "source": "iana"
+  },
+  "text/flexfec": {
+    "source": "iana"
+  },
+  "text/fwdred": {
+    "source": "iana"
+  },
+  "text/gff3": {
+    "source": "iana"
+  },
+  "text/grammar-ref-list": {
+    "source": "iana"
+  },
+  "text/html": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["html","htm","shtml"]
+  },
+  "text/jade": {
+    "extensions": ["jade"]
+  },
+  "text/javascript": {
+    "source": "iana",
+    "compressible": true
+  },
+  "text/jcr-cnd": {
+    "source": "iana"
+  },
+  "text/jsx": {
+    "compressible": true,
+    "extensions": ["jsx"]
+  },
+  "text/less": {
+    "compressible": true,
+    "extensions": ["less"]
+  },
+  "text/markdown": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["markdown","md"]
+  },
+  "text/mathml": {
+    "source": "nginx",
+    "extensions": ["mml"]
+  },
+  "text/mdx": {
+    "compressible": true,
+    "extensions": ["mdx"]
+  },
+  "text/mizar": {
+    "source": "iana"
+  },
+  "text/n3": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["n3"]
+  },
+  "text/parameters": {
+    "source": "iana",
+    "charset": "UTF-8"
+  },
+  "text/parityfec": {
+    "source": "iana"
+  },
+  "text/plain": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["txt","text","conf","def","list","log","in","ini"]
+  },
+  "text/provenance-notation": {
+    "source": "iana",
+    "charset": "UTF-8"
+  },
+  "text/prs.fallenstein.rst": {
+    "source": "iana"
+  },
+  "text/prs.lines.tag": {
+    "source": "iana",
+    "extensions": ["dsc"]
+  },
+  "text/prs.prop.logic": {
+    "source": "iana"
+  },
+  "text/raptorfec": {
+    "source": "iana"
+  },
+  "text/red": {
+    "source": "iana"
+  },
+  "text/rfc822-headers": {
+    "source": "iana"
+  },
+  "text/richtext": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rtx"]
+  },
+  "text/rtf": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["rtf"]
+  },
+  "text/rtp-enc-aescm128": {
+    "source": "iana"
+  },
+  "text/rtploopback": {
+    "source": "iana"
+  },
+  "text/rtx": {
+    "source": "iana"
+  },
+  "text/sgml": {
+    "source": "iana",
+    "extensions": ["sgml","sgm"]
+  },
+  "text/shaclc": {
+    "source": "iana"
+  },
+  "text/shex": {
+    "source": "iana",
+    "extensions": ["shex"]
+  },
+  "text/slim": {
+    "extensions": ["slim","slm"]
+  },
+  "text/spdx": {
+    "source": "iana",
+    "extensions": ["spdx"]
+  },
+  "text/strings": {
+    "source": "iana"
+  },
+  "text/stylus": {
+    "extensions": ["stylus","styl"]
+  },
+  "text/t140": {
+    "source": "iana"
+  },
+  "text/tab-separated-values": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["tsv"]
+  },
+  "text/troff": {
+    "source": "iana",
+    "extensions": ["t","tr","roff","man","me","ms"]
+  },
+  "text/turtle": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "extensions": ["ttl"]
+  },
+  "text/ulpfec": {
+    "source": "iana"
+  },
+  "text/uri-list": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["uri","uris","urls"]
+  },
+  "text/vcard": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["vcard"]
+  },
+  "text/vnd.a": {
+    "source": "iana"
+  },
+  "text/vnd.abc": {
+    "source": "iana"
+  },
+  "text/vnd.ascii-art": {
+    "source": "iana"
+  },
+  "text/vnd.curl": {
+    "source": "iana",
+    "extensions": ["curl"]
+  },
+  "text/vnd.curl.dcurl": {
+    "source": "apache",
+    "extensions": ["dcurl"]
+  },
+  "text/vnd.curl.mcurl": {
+    "source": "apache",
+    "extensions": ["mcurl"]
+  },
+  "text/vnd.curl.scurl": {
+    "source": "apache",
+    "extensions": ["scurl"]
+  },
+  "text/vnd.debian.copyright": {
+    "source": "iana",
+    "charset": "UTF-8"
+  },
+  "text/vnd.dmclientscript": {
+    "source": "iana"
+  },
+  "text/vnd.dvb.subtitle": {
+    "source": "iana",
+    "extensions": ["sub"]
+  },
+  "text/vnd.esmertec.theme-descriptor": {
+    "source": "iana",
+    "charset": "UTF-8"
+  },
+  "text/vnd.familysearch.gedcom": {
+    "source": "iana",
+    "extensions": ["ged"]
+  },
+  "text/vnd.ficlab.flt": {
+    "source": "iana"
+  },
+  "text/vnd.fly": {
+    "source": "iana",
+    "extensions": ["fly"]
+  },
+  "text/vnd.fmi.flexstor": {
+    "source": "iana",
+    "extensions": ["flx"]
+  },
+  "text/vnd.gml": {
+    "source": "iana"
+  },
+  "text/vnd.graphviz": {
+    "source": "iana",
+    "extensions": ["gv"]
+  },
+  "text/vnd.hans": {
+    "source": "iana"
+  },
+  "text/vnd.hgl": {
+    "source": "iana"
+  },
+  "text/vnd.in3d.3dml": {
+    "source": "iana",
+    "extensions": ["3dml"]
+  },
+  "text/vnd.in3d.spot": {
+    "source": "iana",
+    "extensions": ["spot"]
+  },
+  "text/vnd.iptc.newsml": {
+    "source": "iana"
+  },
+  "text/vnd.iptc.nitf": {
+    "source": "iana"
+  },
+  "text/vnd.latex-z": {
+    "source": "iana"
+  },
+  "text/vnd.motorola.reflex": {
+    "source": "iana"
+  },
+  "text/vnd.ms-mediapackage": {
+    "source": "iana"
+  },
+  "text/vnd.net2phone.commcenter.command": {
+    "source": "iana"
+  },
+  "text/vnd.radisys.msml-basic-layout": {
+    "source": "iana"
+  },
+  "text/vnd.senx.warpscript": {
+    "source": "iana"
+  },
+  "text/vnd.si.uricatalogue": {
+    "source": "iana"
+  },
+  "text/vnd.sosi": {
+    "source": "iana"
+  },
+  "text/vnd.sun.j2me.app-descriptor": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "extensions": ["jad"]
+  },
+  "text/vnd.trolltech.linguist": {
+    "source": "iana",
+    "charset": "UTF-8"
+  },
+  "text/vnd.wap.si": {
+    "source": "iana"
+  },
+  "text/vnd.wap.sl": {
+    "source": "iana"
+  },
+  "text/vnd.wap.wml": {
+    "source": "iana",
+    "extensions": ["wml"]
+  },
+  "text/vnd.wap.wmlscript": {
+    "source": "iana",
+    "extensions": ["wmls"]
+  },
+  "text/vtt": {
+    "source": "iana",
+    "charset": "UTF-8",
+    "compressible": true,
+    "extensions": ["vtt"]
+  },
+  "text/x-asm": {
+    "source": "apache",
+    "extensions": ["s","asm"]
+  },
+  "text/x-c": {
+    "source": "apache",
+    "extensions": ["c","cc","cxx","cpp","h","hh","dic"]
+  },
+  "text/x-component": {
+    "source": "nginx",
+    "extensions": ["htc"]
+  },
+  "text/x-fortran": {
+    "source": "apache",
+    "extensions": ["f","for","f77","f90"]
+  },
+  "text/x-gwt-rpc": {
+    "compressible": true
+  },
+  "text/x-handlebars-template": {
+    "extensions": ["hbs"]
+  },
+  "text/x-java-source": {
+    "source": "apache",
+    "extensions": ["java"]
+  },
+  "text/x-jquery-tmpl": {
+    "compressible": true
+  },
+  "text/x-lua": {
+    "extensions": ["lua"]
+  },
+  "text/x-markdown": {
+    "compressible": true,
+    "extensions": ["mkd"]
+  },
+  "text/x-nfo": {
+    "source": "apache",
+    "extensions": ["nfo"]
+  },
+  "text/x-opml": {
+    "source": "apache",
+    "extensions": ["opml"]
+  },
+  "text/x-org": {
+    "compressible": true,
+    "extensions": ["org"]
+  },
+  "text/x-pascal": {
+    "source": "apache",
+    "extensions": ["p","pas"]
+  },
+  "text/x-processing": {
+    "compressible": true,
+    "extensions": ["pde"]
+  },
+  "text/x-sass": {
+    "extensions": ["sass"]
+  },
+  "text/x-scss": {
+    "extensions": ["scss"]
+  },
+  "text/x-setext": {
+    "source": "apache",
+    "extensions": ["etx"]
+  },
+  "text/x-sfv": {
+    "source": "apache",
+    "extensions": ["sfv"]
+  },
+  "text/x-suse-ymp": {
+    "compressible": true,
+    "extensions": ["ymp"]
+  },
+  "text/x-uuencode": {
+    "source": "apache",
+    "extensions": ["uu"]
+  },
+  "text/x-vcalendar": {
+    "source": "apache",
+    "extensions": ["vcs"]
+  },
+  "text/x-vcard": {
+    "source": "apache",
+    "extensions": ["vcf"]
+  },
+  "text/xml": {
+    "source": "iana",
+    "compressible": true,
+    "extensions": ["xml"]
+  },
+  "text/xml-external-parsed-entity": {
+    "source": "iana"
+  },
+  "text/yaml": {
+    "compressible": true,
+    "extensions": ["yaml","yml"]
+  },
+  "video/1d-interleaved-parityfec": {
+    "source": "iana"
+  },
+  "video/3gpp": {
+    "source": "iana",
+    "extensions": ["3gp","3gpp"]
+  },
+  "video/3gpp-tt": {
+    "source": "iana"
+  },
+  "video/3gpp2": {
+    "source": "iana",
+    "extensions": ["3g2"]
+  },
+  "video/av1": {
+    "source": "iana"
+  },
+  "video/bmpeg": {
+    "source": "iana"
+  },
+  "video/bt656": {
+    "source": "iana"
+  },
+  "video/celb": {
+    "source": "iana"
+  },
+  "video/dv": {
+    "source": "iana"
+  },
+  "video/encaprtp": {
+    "source": "iana"
+  },
+  "video/ffv1": {
+    "source": "iana"
+  },
+  "video/flexfec": {
+    "source": "iana"
+  },
+  "video/h261": {
+    "source": "iana",
+    "extensions": ["h261"]
+  },
+  "video/h263": {
+    "source": "iana",
+    "extensions": ["h263"]
+  },
+  "video/h263-1998": {
+    "source": "iana"
+  },
+  "video/h263-2000": {
+    "source": "iana"
+  },
+  "video/h264": {
+    "source": "iana",
+    "extensions": ["h264"]
+  },
+  "video/h264-rcdo": {
+    "source": "iana"
+  },
+  "video/h264-svc": {
+    "source": "iana"
+  },
+  "video/h265": {
+    "source": "iana"
+  },
+  "video/iso.segment": {
+    "source": "iana",
+    "extensions": ["m4s"]
+  },
+  "video/jpeg": {
+    "source": "iana",
+    "extensions": ["jpgv"]
+  },
+  "video/jpeg2000": {
+    "source": "iana"
+  },
+  "video/jpm": {
+    "source": "apache",
+    "extensions": ["jpm","jpgm"]
+  },
+  "video/jxsv": {
+    "source": "iana"
+  },
+  "video/mj2": {
+    "source": "iana",
+    "extensions": ["mj2","mjp2"]
+  },
+  "video/mp1s": {
+    "source": "iana"
+  },
+  "video/mp2p": {
+    "source": "iana"
+  },
+  "video/mp2t": {
+    "source": "iana",
+    "extensions": ["ts"]
+  },
+  "video/mp4": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["mp4","mp4v","mpg4"]
+  },
+  "video/mp4v-es": {
+    "source": "iana"
+  },
+  "video/mpeg": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["mpeg","mpg","mpe","m1v","m2v"]
+  },
+  "video/mpeg4-generic": {
+    "source": "iana"
+  },
+  "video/mpv": {
+    "source": "iana"
+  },
+  "video/nv": {
+    "source": "iana"
+  },
+  "video/ogg": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["ogv"]
+  },
+  "video/parityfec": {
+    "source": "iana"
+  },
+  "video/pointer": {
+    "source": "iana"
+  },
+  "video/quicktime": {
+    "source": "iana",
+    "compressible": false,
+    "extensions": ["qt","mov"]
+  },
+  "video/raptorfec": {
+    "source": "iana"
+  },
+  "video/raw": {
+    "source": "iana"
+  },
+  "video/rtp-enc-aescm128": {
+    "source": "iana"
+  },
+  "video/rtploopback": {
+    "source": "iana"
+  },
+  "video/rtx": {
+    "source": "iana"
+  },
+  "video/scip": {
+    "source": "iana"
+  },
+  "video/smpte291": {
+    "source": "iana"
+  },
+  "video/smpte292m": {
+    "source": "iana"
+  },
+  "video/ulpfec": {
+    "source": "iana"
+  },
+  "video/vc1": {
+    "source": "iana"
+  },
+  "video/vc2": {
+    "source": "iana"
+  },
+  "video/vnd.cctv": {
+    "source": "iana"
+  },
+  "video/vnd.dece.hd": {
+    "source": "iana",
+    "extensions": ["uvh","uvvh"]
+  },
+  "video/vnd.dece.mobile": {
+    "source": "iana",
+    "extensions": ["uvm","uvvm"]
+  },
+  "video/vnd.dece.mp4": {
+    "source": "iana"
+  },
+  "video/vnd.dece.pd": {
+    "source": "iana",
+    "extensions": ["uvp","uvvp"]
+  },
+  "video/vnd.dece.sd": {
+    "source": "iana",
+    "extensions": ["uvs","uvvs"]
+  },
+  "video/vnd.dece.video": {
+    "source": "iana",
+    "extensions": ["uvv","uvvv"]
+  },
+  "video/vnd.directv.mpeg": {
+    "source": "iana"
+  },
+  "video/vnd.directv.mpeg-tts": {
+    "source": "iana"
+  },
+  "video/vnd.dlna.mpeg-tts": {
+    "source": "iana"
+  },
+  "video/vnd.dvb.file": {
+    "source": "iana",
+    "extensions": ["dvb"]
+  },
+  "video/vnd.fvt": {
+    "source": "iana",
+    "extensions": ["fvt"]
+  },
+  "video/vnd.hns.video": {
+    "source": "iana"
+  },
+  "video/vnd.iptvforum.1dparityfec-1010": {
+    "source": "iana"
+  },
+  "video/vnd.iptvforum.1dparityfec-2005": {
+    "source": "iana"
+  },
+  "video/vnd.iptvforum.2dparityfec-1010": {
+    "source": "iana"
+  },
+  "video/vnd.iptvforum.2dparityfec-2005": {
+    "source": "iana"
+  },
+  "video/vnd.iptvforum.ttsavc": {
+    "source": "iana"
+  },
+  "video/vnd.iptvforum.ttsmpeg2": {
+    "source": "iana"
+  },
+  "video/vnd.motorola.video": {
+    "source": "iana"
+  },
+  "video/vnd.motorola.videop": {
+    "source": "iana"
+  },
+  "video/vnd.mpegurl": {
+    "source": "iana",
+    "extensions": ["mxu","m4u"]
+  },
+  "video/vnd.ms-playready.media.pyv": {
+    "source": "iana",
+    "extensions": ["pyv"]
+  },
+  "video/vnd.nokia.interleaved-multimedia": {
+    "source": "iana"
+  },
+  "video/vnd.nokia.mp4vr": {
+    "source": "iana"
+  },
+  "video/vnd.nokia.videovoip": {
+    "source": "iana"
+  },
+  "video/vnd.objectvideo": {
+    "source": "iana"
+  },
+  "video/vnd.radgamettools.bink": {
+    "source": "iana"
+  },
+  "video/vnd.radgamettools.smacker": {
+    "source": "iana"
+  },
+  "video/vnd.sealed.mpeg1": {
+    "source": "iana"
+  },
+  "video/vnd.sealed.mpeg4": {
+    "source": "iana"
+  },
+  "video/vnd.sealed.swf": {
+    "source": "iana"
+  },
+  "video/vnd.sealedmedia.softseal.mov": {
+    "source": "iana"
+  },
+  "video/vnd.uvvu.mp4": {
+    "source": "iana",
+    "extensions": ["uvu","uvvu"]
+  },
+  "video/vnd.vivo": {
+    "source": "iana",
+    "extensions": ["viv"]
+  },
+  "video/vnd.youtube.yt": {
+    "source": "iana"
+  },
+  "video/vp8": {
+    "source": "iana"
+  },
+  "video/vp9": {
+    "source": "iana"
+  },
+  "video/webm": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["webm"]
+  },
+  "video/x-f4v": {
+    "source": "apache",
+    "extensions": ["f4v"]
+  },
+  "video/x-fli": {
+    "source": "apache",
+    "extensions": ["fli"]
+  },
+  "video/x-flv": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["flv"]
+  },
+  "video/x-m4v": {
+    "source": "apache",
+    "extensions": ["m4v"]
+  },
+  "video/x-matroska": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["mkv","mk3d","mks"]
+  },
+  "video/x-mng": {
+    "source": "apache",
+    "extensions": ["mng"]
+  },
+  "video/x-ms-asf": {
+    "source": "apache",
+    "extensions": ["asf","asx"]
+  },
+  "video/x-ms-vob": {
+    "source": "apache",
+    "extensions": ["vob"]
+  },
+  "video/x-ms-wm": {
+    "source": "apache",
+    "extensions": ["wm"]
+  },
+  "video/x-ms-wmv": {
+    "source": "apache",
+    "compressible": false,
+    "extensions": ["wmv"]
+  },
+  "video/x-ms-wmx": {
+    "source": "apache",
+    "extensions": ["wmx"]
+  },
+  "video/x-ms-wvx": {
+    "source": "apache",
+    "extensions": ["wvx"]
+  },
+  "video/x-msvideo": {
+    "source": "apache",
+    "extensions": ["avi"]
+  },
+  "video/x-sgi-movie": {
+    "source": "apache",
+    "extensions": ["movie"]
+  },
+  "video/x-smv": {
+    "source": "apache",
+    "extensions": ["smv"]
+  },
+  "x-conference/x-cooltalk": {
+    "source": "apache",
+    "extensions": ["ice"]
+  },
+  "x-shader/x-fragment": {
+    "compressible": true
+  },
+  "x-shader/x-vertex": {
+    "compressible": true
+  }
+}

+ 12 - 0
node_modules/mime-db/index.js

@@ -0,0 +1,12 @@
+/*!
+ * mime-db
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2015-2022 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+/**
+ * Module exports.
+ */
+
+module.exports = require('./db.json')

+ 60 - 0
node_modules/mime-db/package.json

@@ -0,0 +1,60 @@
+{
+  "name": "mime-db",
+  "description": "Media Type Database",
+  "version": "1.52.0",
+  "contributors": [
+    "Douglas Christopher Wilson <doug@somethingdoug.com>",
+    "Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)",
+    "Robert Kieffer <robert@broofa.com> (http://github.com/broofa)"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "mime",
+    "db",
+    "type",
+    "types",
+    "database",
+    "charset",
+    "charsets"
+  ],
+  "repository": "jshttp/mime-db",
+  "devDependencies": {
+    "bluebird": "3.7.2",
+    "co": "4.6.0",
+    "cogent": "1.0.1",
+    "csv-parse": "4.16.3",
+    "eslint": "7.32.0",
+    "eslint-config-standard": "15.0.1",
+    "eslint-plugin-import": "2.25.4",
+    "eslint-plugin-markdown": "2.2.1",
+    "eslint-plugin-node": "11.1.0",
+    "eslint-plugin-promise": "5.1.1",
+    "eslint-plugin-standard": "4.1.0",
+    "gnode": "0.1.2",
+    "media-typer": "1.1.0",
+    "mocha": "9.2.1",
+    "nyc": "15.1.0",
+    "raw-body": "2.5.0",
+    "stream-to-array": "2.3.0"
+  },
+  "files": [
+    "HISTORY.md",
+    "LICENSE",
+    "README.md",
+    "db.json",
+    "index.js"
+  ],
+  "engines": {
+    "node": ">= 0.6"
+  },
+  "scripts": {
+    "build": "node scripts/build",
+    "fetch": "node scripts/fetch-apache && gnode scripts/fetch-iana && node scripts/fetch-nginx",
+    "lint": "eslint .",
+    "test": "mocha --reporter spec --bail --check-leaks test/",
+    "test-ci": "nyc --reporter=lcov --reporter=text npm test",
+    "test-cov": "nyc --reporter=html --reporter=text npm test",
+    "update": "npm run fetch && npm run build",
+    "version": "node scripts/version-history.js && git add HISTORY.md"
+  }
+}

+ 397 - 0
node_modules/mime-types/HISTORY.md

@@ -0,0 +1,397 @@
+2.1.35 / 2022-03-12
+===================
+
+  * deps: mime-db@1.52.0
+    - Add extensions from IANA for more `image/*` types
+    - Add extension `.asc` to `application/pgp-keys`
+    - Add extensions to various XML types
+    - Add new upstream MIME types
+
+2.1.34 / 2021-11-08
+===================
+
+  * deps: mime-db@1.51.0
+    - Add new upstream MIME types
+
+2.1.33 / 2021-10-01
+===================
+
+  * deps: mime-db@1.50.0
+    - Add deprecated iWorks mime types and extensions
+    - Add new upstream MIME types
+
+2.1.32 / 2021-07-27
+===================
+
+  * deps: mime-db@1.49.0
+    - Add extension `.trig` to `application/trig`
+    - Add new upstream MIME types
+
+2.1.31 / 2021-06-01
+===================
+
+  * deps: mime-db@1.48.0
+    - Add extension `.mvt` to `application/vnd.mapbox-vector-tile`
+    - Add new upstream MIME types
+
+2.1.30 / 2021-04-02
+===================
+
+  * deps: mime-db@1.47.0
+    - Add extension `.amr` to `audio/amr`
+    - Remove ambigious extensions from IANA for `application/*+xml` types
+    - Update primary extension to `.es` for `application/ecmascript`
+
+2.1.29 / 2021-02-17
+===================
+
+  * deps: mime-db@1.46.0
+    - Add extension `.amr` to `audio/amr`
+    - Add extension `.m4s` to `video/iso.segment`
+    - Add extension `.opus` to `audio/ogg`
+    - Add new upstream MIME types
+
+2.1.28 / 2021-01-01
+===================
+
+  * deps: mime-db@1.45.0
+    - Add `application/ubjson` with extension `.ubj`
+    - Add `image/avif` with extension `.avif`
+    - Add `image/ktx2` with extension `.ktx2`
+    - Add extension `.dbf` to `application/vnd.dbf`
+    - Add extension `.rar` to `application/vnd.rar`
+    - Add extension `.td` to `application/urc-targetdesc+xml`
+    - Add new upstream MIME types
+    - Fix extension of `application/vnd.apple.keynote` to be `.key`
+
+2.1.27 / 2020-04-23
+===================
+
+  * deps: mime-db@1.44.0
+    - Add charsets from IANA
+    - Add extension `.cjs` to `application/node`
+    - Add new upstream MIME types
+
+2.1.26 / 2020-01-05
+===================
+
+  * deps: mime-db@1.43.0
+    - Add `application/x-keepass2` with extension `.kdbx`
+    - Add extension `.mxmf` to `audio/mobile-xmf`
+    - Add extensions from IANA for `application/*+xml` types
+    - Add new upstream MIME types
+
+2.1.25 / 2019-11-12
+===================
+
+  * deps: mime-db@1.42.0
+    - Add new upstream MIME types
+    - Add `application/toml` with extension `.toml`
+    - Add `image/vnd.ms-dds` with extension `.dds`
+
+2.1.24 / 2019-04-20
+===================
+
+  * deps: mime-db@1.40.0
+    - Add extensions from IANA for `model/*` types
+    - Add `text/mdx` with extension `.mdx`
+
+2.1.23 / 2019-04-17
+===================
+
+  * deps: mime-db@~1.39.0
+    - Add extensions `.siv` and `.sieve` to `application/sieve`
+    - Add new upstream MIME types
+
+2.1.22 / 2019-02-14
+===================
+
+  * deps: mime-db@~1.38.0
+    - Add extension `.nq` to `application/n-quads`
+    - Add extension `.nt` to `application/n-triples`
+    - Add new upstream MIME types
+
+2.1.21 / 2018-10-19
+===================
+
+  * deps: mime-db@~1.37.0
+    - Add extensions to HEIC image types
+    - Add new upstream MIME types
+
+2.1.20 / 2018-08-26
+===================
+
+  * deps: mime-db@~1.36.0
+    - Add Apple file extensions from IANA
+    - Add extensions from IANA for `image/*` types
+    - Add new upstream MIME types
+
+2.1.19 / 2018-07-17
+===================
+
+  * deps: mime-db@~1.35.0
+    - Add extension `.csl` to `application/vnd.citationstyles.style+xml`
+    - Add extension `.es` to `application/ecmascript`
+    - Add extension `.owl` to `application/rdf+xml`
+    - Add new upstream MIME types
+    - Add UTF-8 as default charset for `text/turtle`
+
+2.1.18 / 2018-02-16
+===================
+
+  * deps: mime-db@~1.33.0
+    - Add `application/raml+yaml` with extension `.raml`
+    - Add `application/wasm` with extension `.wasm`
+    - Add `text/shex` with extension `.shex`
+    - Add extensions for JPEG-2000 images
+    - Add extensions from IANA for `message/*` types
+    - Add new upstream MIME types
+    - Update font MIME types
+    - Update `text/hjson` to registered `application/hjson`
+
+2.1.17 / 2017-09-01
+===================
+
+  * deps: mime-db@~1.30.0
+    - Add `application/vnd.ms-outlook`
+    - Add `application/x-arj`
+    - Add extension `.mjs` to `application/javascript`
+    - Add glTF types and extensions
+    - Add new upstream MIME types
+    - Add `text/x-org`
+    - Add VirtualBox MIME types
+    - Fix `source` records for `video/*` types that are IANA
+    - Update `font/opentype` to registered `font/otf`
+
+2.1.16 / 2017-07-24
+===================
+
+  * deps: mime-db@~1.29.0
+    - Add `application/fido.trusted-apps+json`
+    - Add extension `.wadl` to `application/vnd.sun.wadl+xml`
+    - Add extension `.gz` to `application/gzip`
+    - Add new upstream MIME types
+    - Update extensions `.md` and `.markdown` to be `text/markdown`
+
+2.1.15 / 2017-03-23
+===================
+
+  * deps: mime-db@~1.27.0
+    - Add new mime types
+    - Add `image/apng`
+
+2.1.14 / 2017-01-14
+===================
+
+  * deps: mime-db@~1.26.0
+    - Add new mime types
+
+2.1.13 / 2016-11-18
+===================
+
+  * deps: mime-db@~1.25.0
+    - Add new mime types
+
+2.1.12 / 2016-09-18
+===================
+
+  * deps: mime-db@~1.24.0
+    - Add new mime types
+    - Add `audio/mp3`
+
+2.1.11 / 2016-05-01
+===================
+
+  * deps: mime-db@~1.23.0
+    - Add new mime types
+
+2.1.10 / 2016-02-15
+===================
+
+  * deps: mime-db@~1.22.0
+    - Add new mime types
+    - Fix extension of `application/dash+xml`
+    - Update primary extension for `audio/mp4`
+
+2.1.9 / 2016-01-06
+==================
+
+  * deps: mime-db@~1.21.0
+    - Add new mime types
+
+2.1.8 / 2015-11-30
+==================
+
+  * deps: mime-db@~1.20.0
+    - Add new mime types
+
+2.1.7 / 2015-09-20
+==================
+
+  * deps: mime-db@~1.19.0
+    - Add new mime types
+
+2.1.6 / 2015-09-03
+==================
+
+  * deps: mime-db@~1.18.0
+    - Add new mime types
+
+2.1.5 / 2015-08-20
+==================
+
+  * deps: mime-db@~1.17.0
+    - Add new mime types
+
+2.1.4 / 2015-07-30
+==================
+
+  * deps: mime-db@~1.16.0
+    - Add new mime types
+
+2.1.3 / 2015-07-13
+==================
+
+  * deps: mime-db@~1.15.0
+    - Add new mime types
+
+2.1.2 / 2015-06-25
+==================
+
+  * deps: mime-db@~1.14.0
+    - Add new mime types
+
+2.1.1 / 2015-06-08
+==================
+
+  * perf: fix deopt during mapping
+
+2.1.0 / 2015-06-07
+==================
+
+  * Fix incorrectly treating extension-less file name as extension
+    - i.e. `'path/to/json'` will no longer return `application/json`
+  * Fix `.charset(type)` to accept parameters
+  * Fix `.charset(type)` to match case-insensitive
+  * Improve generation of extension to MIME mapping
+  * Refactor internals for readability and no argument reassignment
+  * Prefer `application/*` MIME types from the same source
+  * Prefer any type over `application/octet-stream`
+  * deps: mime-db@~1.13.0
+    - Add nginx as a source
+    - Add new mime types
+
+2.0.14 / 2015-06-06
+===================
+
+  * deps: mime-db@~1.12.0
+    - Add new mime types
+
+2.0.13 / 2015-05-31
+===================
+
+  * deps: mime-db@~1.11.0
+    - Add new mime types
+
+2.0.12 / 2015-05-19
+===================
+
+  * deps: mime-db@~1.10.0
+    - Add new mime types
+
+2.0.11 / 2015-05-05
+===================
+
+  * deps: mime-db@~1.9.1
+    - Add new mime types
+
+2.0.10 / 2015-03-13
+===================
+
+  * deps: mime-db@~1.8.0
+    - Add new mime types
+
+2.0.9 / 2015-02-09
+==================
+
+  * deps: mime-db@~1.7.0
+    - Add new mime types
+    - Community extensions ownership transferred from `node-mime`
+
+2.0.8 / 2015-01-29
+==================
+
+  * deps: mime-db@~1.6.0
+    - Add new mime types
+
+2.0.7 / 2014-12-30
+==================
+
+  * deps: mime-db@~1.5.0
+    - Add new mime types
+    - Fix various invalid MIME type entries
+
+2.0.6 / 2014-12-30
+==================
+
+  * deps: mime-db@~1.4.0
+    - Add new mime types
+    - Fix various invalid MIME type entries
+    - Remove example template MIME types
+
+2.0.5 / 2014-12-29
+==================
+
+  * deps: mime-db@~1.3.1
+    - Fix missing extensions
+
+2.0.4 / 2014-12-10
+==================
+
+  * deps: mime-db@~1.3.0
+    - Add new mime types
+
+2.0.3 / 2014-11-09
+==================
+
+  * deps: mime-db@~1.2.0
+    - Add new mime types
+
+2.0.2 / 2014-09-28
+==================
+
+  * deps: mime-db@~1.1.0
+    - Add new mime types
+    - Update charsets
+
+2.0.1 / 2014-09-07
+==================
+
+  * Support Node.js 0.6
+
+2.0.0 / 2014-09-02
+==================
+
+  * Use `mime-db`
+  * Remove `.define()`
+
+1.0.2 / 2014-08-04
+==================
+
+  * Set charset=utf-8 for `text/javascript`
+
+1.0.1 / 2014-06-24
+==================
+
+  * Add `text/jsx` type
+
+1.0.0 / 2014-05-12
+==================
+
+  * Return `false` for unknown types
+  * Set charset=utf-8 for `application/json`
+
+0.1.0 / 2014-05-02
+==================
+
+  * Initial release

+ 23 - 0
node_modules/mime-types/LICENSE

@@ -0,0 +1,23 @@
+(The MIT License)
+
+Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
+Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 113 - 0
node_modules/mime-types/README.md

@@ -0,0 +1,113 @@
+# mime-types
+
+[![NPM Version][npm-version-image]][npm-url]
+[![NPM Downloads][npm-downloads-image]][npm-url]
+[![Node.js Version][node-version-image]][node-version-url]
+[![Build Status][ci-image]][ci-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+
+The ultimate javascript content-type utility.
+
+Similar to [the `mime@1.x` module](https://www.npmjs.com/package/mime), except:
+
+- __No fallbacks.__ Instead of naively returning the first available type,
+  `mime-types` simply returns `false`, so do
+  `var type = mime.lookup('unrecognized') || 'application/octet-stream'`.
+- No `new Mime()` business, so you could do `var lookup = require('mime-types').lookup`.
+- No `.define()` functionality
+- Bug fixes for `.lookup(path)`
+
+Otherwise, the API is compatible with `mime` 1.x.
+
+## Install
+
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/). Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
+```sh
+$ npm install mime-types
+```
+
+## Adding Types
+
+All mime types are based on [mime-db](https://www.npmjs.com/package/mime-db),
+so open a PR there if you'd like to add mime types.
+
+## API
+
+```js
+var mime = require('mime-types')
+```
+
+All functions return `false` if input is invalid or not found.
+
+### mime.lookup(path)
+
+Lookup the content-type associated with a file.
+
+```js
+mime.lookup('json') // 'application/json'
+mime.lookup('.md') // 'text/markdown'
+mime.lookup('file.html') // 'text/html'
+mime.lookup('folder/file.js') // 'application/javascript'
+mime.lookup('folder/.htaccess') // false
+
+mime.lookup('cats') // false
+```
+
+### mime.contentType(type)
+
+Create a full content-type header given a content-type or extension.
+When given an extension, `mime.lookup` is used to get the matching
+content-type, otherwise the given content-type is used. Then if the
+content-type does not already have a `charset` parameter, `mime.charset`
+is used to get the default charset and add to the returned content-type.
+
+```js
+mime.contentType('markdown') // 'text/x-markdown; charset=utf-8'
+mime.contentType('file.json') // 'application/json; charset=utf-8'
+mime.contentType('text/html') // 'text/html; charset=utf-8'
+mime.contentType('text/html; charset=iso-8859-1') // 'text/html; charset=iso-8859-1'
+
+// from a full path
+mime.contentType(path.extname('/path/to/file.json')) // 'application/json; charset=utf-8'
+```
+
+### mime.extension(type)
+
+Get the default extension for a content-type.
+
+```js
+mime.extension('application/octet-stream') // 'bin'
+```
+
+### mime.charset(type)
+
+Lookup the implied default charset of a content-type.
+
+```js
+mime.charset('text/markdown') // 'UTF-8'
+```
+
+### var type = mime.types[extension]
+
+A map of content-types by extension.
+
+### [extensions...] = mime.extensions[type]
+
+A map of extensions by content-type.
+
+## License
+
+[MIT](LICENSE)
+
+[ci-image]: https://badgen.net/github/checks/jshttp/mime-types/master?label=ci
+[ci-url]: https://github.com/jshttp/mime-types/actions/workflows/ci.yml
+[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-types/master
+[coveralls-url]: https://coveralls.io/r/jshttp/mime-types?branch=master
+[node-version-image]: https://badgen.net/npm/node/mime-types
+[node-version-url]: https://nodejs.org/en/download
+[npm-downloads-image]: https://badgen.net/npm/dm/mime-types
+[npm-url]: https://npmjs.org/package/mime-types
+[npm-version-image]: https://badgen.net/npm/v/mime-types

+ 188 - 0
node_modules/mime-types/index.js

@@ -0,0 +1,188 @@
+/*!
+ * mime-types
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var db = require('mime-db')
+var extname = require('path').extname
+
+/**
+ * Module variables.
+ * @private
+ */
+
+var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/
+var TEXT_TYPE_REGEXP = /^text\//i
+
+/**
+ * Module exports.
+ * @public
+ */
+
+exports.charset = charset
+exports.charsets = { lookup: charset }
+exports.contentType = contentType
+exports.extension = extension
+exports.extensions = Object.create(null)
+exports.lookup = lookup
+exports.types = Object.create(null)
+
+// Populate the extensions/types maps
+populateMaps(exports.extensions, exports.types)
+
+/**
+ * Get the default charset for a MIME type.
+ *
+ * @param {string} type
+ * @return {boolean|string}
+ */
+
+function charset (type) {
+  if (!type || typeof type !== 'string') {
+    return false
+  }
+
+  // TODO: use media-typer
+  var match = EXTRACT_TYPE_REGEXP.exec(type)
+  var mime = match && db[match[1].toLowerCase()]
+
+  if (mime && mime.charset) {
+    return mime.charset
+  }
+
+  // default text/* to utf-8
+  if (match && TEXT_TYPE_REGEXP.test(match[1])) {
+    return 'UTF-8'
+  }
+
+  return false
+}
+
+/**
+ * Create a full Content-Type header given a MIME type or extension.
+ *
+ * @param {string} str
+ * @return {boolean|string}
+ */
+
+function contentType (str) {
+  // TODO: should this even be in this module?
+  if (!str || typeof str !== 'string') {
+    return false
+  }
+
+  var mime = str.indexOf('/') === -1
+    ? exports.lookup(str)
+    : str
+
+  if (!mime) {
+    return false
+  }
+
+  // TODO: use content-type or other module
+  if (mime.indexOf('charset') === -1) {
+    var charset = exports.charset(mime)
+    if (charset) mime += '; charset=' + charset.toLowerCase()
+  }
+
+  return mime
+}
+
+/**
+ * Get the default extension for a MIME type.
+ *
+ * @param {string} type
+ * @return {boolean|string}
+ */
+
+function extension (type) {
+  if (!type || typeof type !== 'string') {
+    return false
+  }
+
+  // TODO: use media-typer
+  var match = EXTRACT_TYPE_REGEXP.exec(type)
+
+  // get extensions
+  var exts = match && exports.extensions[match[1].toLowerCase()]
+
+  if (!exts || !exts.length) {
+    return false
+  }
+
+  return exts[0]
+}
+
+/**
+ * Lookup the MIME type for a file path/extension.
+ *
+ * @param {string} path
+ * @return {boolean|string}
+ */
+
+function lookup (path) {
+  if (!path || typeof path !== 'string') {
+    return false
+  }
+
+  // get the extension ("ext" or ".ext" or full path)
+  var extension = extname('x.' + path)
+    .toLowerCase()
+    .substr(1)
+
+  if (!extension) {
+    return false
+  }
+
+  return exports.types[extension] || false
+}
+
+/**
+ * Populate the extensions and types maps.
+ * @private
+ */
+
+function populateMaps (extensions, types) {
+  // source preference (least -> most)
+  var preference = ['nginx', 'apache', undefined, 'iana']
+
+  Object.keys(db).forEach(function forEachMimeType (type) {
+    var mime = db[type]
+    var exts = mime.extensions
+
+    if (!exts || !exts.length) {
+      return
+    }
+
+    // mime -> extensions
+    extensions[type] = exts
+
+    // extension -> mime
+    for (var i = 0; i < exts.length; i++) {
+      var extension = exts[i]
+
+      if (types[extension]) {
+        var from = preference.indexOf(db[types[extension]].source)
+        var to = preference.indexOf(mime.source)
+
+        if (types[extension] !== 'application/octet-stream' &&
+          (from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {
+          // skip the remapping
+          continue
+        }
+      }
+
+      // set the extension -> mime
+      types[extension] = type
+    }
+  })
+}

+ 44 - 0
node_modules/mime-types/package.json

@@ -0,0 +1,44 @@
+{
+  "name": "mime-types",
+  "description": "The ultimate javascript content-type utility.",
+  "version": "2.1.35",
+  "contributors": [
+    "Douglas Christopher Wilson <doug@somethingdoug.com>",
+    "Jeremiah Senkpiel <fishrock123@rocketmail.com> (https://searchbeam.jit.su)",
+    "Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "mime",
+    "types"
+  ],
+  "repository": "jshttp/mime-types",
+  "dependencies": {
+    "mime-db": "1.52.0"
+  },
+  "devDependencies": {
+    "eslint": "7.32.0",
+    "eslint-config-standard": "14.1.1",
+    "eslint-plugin-import": "2.25.4",
+    "eslint-plugin-markdown": "2.2.1",
+    "eslint-plugin-node": "11.1.0",
+    "eslint-plugin-promise": "5.2.0",
+    "eslint-plugin-standard": "4.1.0",
+    "mocha": "9.2.2",
+    "nyc": "15.1.0"
+  },
+  "files": [
+    "HISTORY.md",
+    "LICENSE",
+    "index.js"
+  ],
+  "engines": {
+    "node": ">= 0.6"
+  },
+  "scripts": {
+    "lint": "eslint .",
+    "test": "mocha --reporter spec test/test.js",
+    "test-ci": "nyc --reporter=lcov --reporter=text npm test",
+    "test-cov": "nyc --reporter=html --reporter=text npm test"
+  }
+}

+ 29 - 0
node_modules/minimist/.eslintrc

@@ -0,0 +1,29 @@
+{
+	"root": true,
+
+	"extends": "@ljharb/eslint-config/node/0.4",
+
+	"rules": {
+		"array-element-newline": 0,
+		"complexity": 0,
+		"func-style": [2, "declaration"],
+		"max-lines-per-function": 0,
+		"max-nested-callbacks": 1,
+		"max-statements-per-line": 1,
+		"max-statements": 0,
+		"multiline-comment-style": 0,
+		"no-continue": 1,
+		"no-param-reassign": 1,
+		"no-restricted-syntax": 1,
+		"object-curly-newline": 0,
+	},
+
+	"overrides": [
+		{
+			"files": "test/**",
+			"rules": {
+				"camelcase": 0,
+			},
+		},
+	]
+}

+ 12 - 0
node_modules/minimist/.github/FUNDING.yml

@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: [ljharb]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: npm/minimist
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

+ 14 - 0
node_modules/minimist/.nycrc

@@ -0,0 +1,14 @@
+{
+	"all": true,
+	"check-coverage": false,
+	"reporter": ["text-summary", "text", "html", "json"],
+	"lines": 86,
+	"statements": 85.93,
+	"functions": 82.43,
+	"branches": 76.06,
+	"exclude": [
+		"coverage",
+		"example",
+		"test"
+	]
+}

+ 298 - 0
node_modules/minimist/CHANGELOG.md

@@ -0,0 +1,298 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [v1.2.8](https://github.com/minimistjs/minimist/compare/v1.2.7...v1.2.8) - 2023-02-09
+
+### Merged
+
+- [Fix] Fix long option followed by single dash [`#17`](https://github.com/minimistjs/minimist/pull/17)
+- [Tests] Remove duplicate test [`#12`](https://github.com/minimistjs/minimist/pull/12)
+- [Fix] opt.string works with multiple aliases [`#10`](https://github.com/minimistjs/minimist/pull/10)
+
+### Fixed
+
+- [Fix] Fix long option followed by single dash (#17) [`#15`](https://github.com/minimistjs/minimist/issues/15)
+- [Tests] Remove duplicate test (#12) [`#8`](https://github.com/minimistjs/minimist/issues/8)
+- [Fix] Fix long option followed by single dash [`#15`](https://github.com/minimistjs/minimist/issues/15)
+- [Fix] opt.string works with multiple aliases (#10) [`#9`](https://github.com/minimistjs/minimist/issues/9)
+- [Fix] Fix handling of short option with non-trivial equals [`#5`](https://github.com/minimistjs/minimist/issues/5)
+- [Tests] Remove duplicate test [`#8`](https://github.com/minimistjs/minimist/issues/8)
+- [Fix] opt.string works with multiple aliases [`#9`](https://github.com/minimistjs/minimist/issues/9)
+
+### Commits
+
+- Merge tag 'v0.2.3' [`a026794`](https://github.com/minimistjs/minimist/commit/a0267947c7870fc5847cf2d437fbe33f392767da)
+- [eslint] fix indentation and whitespace [`5368ca4`](https://github.com/minimistjs/minimist/commit/5368ca4147e974138a54cc0dc4cea8f756546b70)
+- [eslint] fix indentation and whitespace [`e5f5067`](https://github.com/minimistjs/minimist/commit/e5f5067259ceeaf0b098d14bec910f87e58708c7)
+- [eslint] more cleanup [`62fde7d`](https://github.com/minimistjs/minimist/commit/62fde7d935f83417fb046741531a9e2346a36976)
+- [eslint] more cleanup [`36ac5d0`](https://github.com/minimistjs/minimist/commit/36ac5d0d95e4947d074e5737d94814034ca335d1)
+- [meta] add `auto-changelog` [`73923d2`](https://github.com/minimistjs/minimist/commit/73923d223553fca08b1ba77e3fbc2a492862ae4c)
+- [actions] add reusable workflows [`d80727d`](https://github.com/minimistjs/minimist/commit/d80727df77bfa9e631044d7f16368d8f09242c91)
+- [eslint] add eslint; rules to enable later are warnings [`48bc06a`](https://github.com/minimistjs/minimist/commit/48bc06a1b41f00e9cdf183db34f7a51ba70e98d4)
+- [eslint] fix indentation [`34b0f1c`](https://github.com/minimistjs/minimist/commit/34b0f1ccaa45183c3c4f06a91f9b405180a6f982)
+- [readme] rename and add badges [`5df0fe4`](https://github.com/minimistjs/minimist/commit/5df0fe49211bd09a3636f8686a7cb3012c3e98f0)
+- [Dev Deps] switch from `covert` to `nyc` [`a48b128`](https://github.com/minimistjs/minimist/commit/a48b128fdb8d427dfb20a15273f83e38d97bef07)
+- [Dev Deps] update `covert`, `tape`; remove unnecessary `tap` [`f0fb958`](https://github.com/minimistjs/minimist/commit/f0fb958e9a1fe980cdffc436a211b0bda58f621b)
+- [meta] create FUNDING.yml; add `funding` in package.json [`3639e0c`](https://github.com/minimistjs/minimist/commit/3639e0c819359a366387e425ab6eabf4c78d3caa)
+- [meta] use `npmignore` to autogenerate an npmignore file [`be2e038`](https://github.com/minimistjs/minimist/commit/be2e038c342d8333b32f0fde67a0026b79c8150e)
+- Only apps should have lockfiles [`282b570`](https://github.com/minimistjs/minimist/commit/282b570e7489d01b03f2d6d3dabf79cd3e5f84cf)
+- isConstructorOrProto adapted from PR [`ef9153f`](https://github.com/minimistjs/minimist/commit/ef9153fc52b6cea0744b2239921c5dcae4697f11)
+- [Dev Deps] update `@ljharb/eslint-config`, `aud` [`098873c`](https://github.com/minimistjs/minimist/commit/098873c213cdb7c92e55ae1ef5aa1af3a8192a79)
+- [Dev Deps] update `@ljharb/eslint-config`, `aud` [`3124ed3`](https://github.com/minimistjs/minimist/commit/3124ed3e46306301ebb3c834874ce0241555c2c4)
+- [meta] add `safe-publish-latest` [`4b927de`](https://github.com/minimistjs/minimist/commit/4b927de696d561c636b4f43bf49d4597cb36d6d6)
+- [Tests] add `aud` in `posttest` [`b32d9bd`](https://github.com/minimistjs/minimist/commit/b32d9bd0ab340f4e9f8c3a97ff2a4424f25fab8c)
+- [meta] update repo URLs [`f9fdfc0`](https://github.com/minimistjs/minimist/commit/f9fdfc032c54884d9a9996a390c63cd0719bbe1a)
+- [actions] Avoid 0.6 tests due to build failures [`ba92fe6`](https://github.com/minimistjs/minimist/commit/ba92fe6ebbdc0431cca9a2ea8f27beb492f5e4ec)
+- [Dev Deps] update `tape` [`950eaa7`](https://github.com/minimistjs/minimist/commit/950eaa74f112e04d23e9c606c67472c46739b473)
+- [Dev Deps] add missing `npmignore` dev dep [`3226afa`](https://github.com/minimistjs/minimist/commit/3226afaf09e9d127ca369742437fe6e88f752d6b)
+- Merge tag 'v0.2.2' [`980d7ac`](https://github.com/minimistjs/minimist/commit/980d7ac61a0b4bd552711251ac107d506b23e41f)
+
+## [v1.2.7](https://github.com/minimistjs/minimist/compare/v1.2.6...v1.2.7) - 2022-10-10
+
+### Commits
+
+- [meta] add `auto-changelog` [`0ebf4eb`](https://github.com/minimistjs/minimist/commit/0ebf4ebcd5f7787a5524d31a849ef41316b83c3c)
+- [actions] add reusable workflows [`e115b63`](https://github.com/minimistjs/minimist/commit/e115b63fa9d3909f33b00a2db647ff79068388de)
+- [eslint] add eslint; rules to enable later are warnings [`f58745b`](https://github.com/minimistjs/minimist/commit/f58745b9bb84348e1be72af7dbba5840c7c13013)
+- [Dev Deps] switch from `covert` to `nyc` [`ab03356`](https://github.com/minimistjs/minimist/commit/ab033567b9c8b31117cb026dc7f1e592ce455c65)
+- [readme] rename and add badges [`236f4a0`](https://github.com/minimistjs/minimist/commit/236f4a07e4ebe5ee44f1496ec6974991ab293ffd)
+- [meta] create FUNDING.yml; add `funding` in package.json [`783a49b`](https://github.com/minimistjs/minimist/commit/783a49bfd47e8335d3098a8cac75662cf71eb32a)
+- [meta] use `npmignore` to autogenerate an npmignore file [`f81ece6`](https://github.com/minimistjs/minimist/commit/f81ece6aaec2fa14e69ff4f1e0407a8c4e2635a2)
+- Only apps should have lockfiles [`56cad44`](https://github.com/minimistjs/minimist/commit/56cad44c7f879b9bb5ec18fcc349308024a89bfc)
+- [Dev Deps] update `covert`, `tape`; remove unnecessary `tap` [`49c5f9f`](https://github.com/minimistjs/minimist/commit/49c5f9fb7e6a92db9eb340cc679de92fb3aacded)
+- [Tests] add `aud` in `posttest` [`228ae93`](https://github.com/minimistjs/minimist/commit/228ae938f3cd9db9dfd8bd7458b076a7b2aef280)
+- [meta] add `safe-publish-latest` [`01fc23f`](https://github.com/minimistjs/minimist/commit/01fc23f5104f85c75059972e01dd33796ab529ff)
+- [meta] update repo URLs [`6b164c7`](https://github.com/minimistjs/minimist/commit/6b164c7d68e0b6bf32f894699effdfb7c63041dd)
+
+## [v1.2.6](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.6) - 2022-03-21
+
+### Commits
+
+- test from prototype pollution PR [`bc8ecee`](https://github.com/minimistjs/minimist/commit/bc8ecee43875261f4f17eb20b1243d3ed15e70eb)
+- isConstructorOrProto adapted from PR [`c2b9819`](https://github.com/minimistjs/minimist/commit/c2b981977fa834b223b408cfb860f933c9811e4d)
+- security notice for additional prototype pollution issue [`ef88b93`](https://github.com/minimistjs/minimist/commit/ef88b9325f77b5ee643ccfc97e2ebda577e4c4e2)
+
+## [v1.2.5](https://github.com/minimistjs/minimist/compare/v1.2.4...v1.2.5) - 2020-03-12
+
+## [v1.2.4](https://github.com/minimistjs/minimist/compare/v1.2.3...v1.2.4) - 2020-03-11
+
+### Commits
+
+- security notice [`4cf1354`](https://github.com/minimistjs/minimist/commit/4cf1354839cb972e38496d35e12f806eea92c11f)
+- additional test for constructor prototype pollution [`1043d21`](https://github.com/minimistjs/minimist/commit/1043d212c3caaf871966e710f52cfdf02f9eea4b)
+
+## [v1.2.3](https://github.com/minimistjs/minimist/compare/v1.2.2...v1.2.3) - 2020-03-10
+
+### Commits
+
+- more failing proto pollution tests [`13c01a5`](https://github.com/minimistjs/minimist/commit/13c01a5327736903704984b7f65616b8476850cc)
+- even more aggressive checks for protocol pollution [`38a4d1c`](https://github.com/minimistjs/minimist/commit/38a4d1caead72ef99e824bb420a2528eec03d9ab)
+
+## [v1.2.2](https://github.com/minimistjs/minimist/compare/v1.2.1...v1.2.2) - 2020-03-10
+
+### Commits
+
+- failing test for protocol pollution [`0efed03`](https://github.com/minimistjs/minimist/commit/0efed0340ec8433638758f7ca0c77cb20a0bfbab)
+- cleanup [`67d3722`](https://github.com/minimistjs/minimist/commit/67d3722413448d00a62963d2d30c34656a92d7e2)
+- console.dir -&gt; console.log [`47acf72`](https://github.com/minimistjs/minimist/commit/47acf72c715a630bf9ea013867f47f1dd69dfc54)
+- don't assign onto __proto__ [`63e7ed0`](https://github.com/minimistjs/minimist/commit/63e7ed05aa4b1889ec2f3b196426db4500cbda94)
+
+## [v1.2.1](https://github.com/minimistjs/minimist/compare/v1.2.0...v1.2.1) - 2020-03-10
+
+### Merged
+
+- move the `opts['--']` example back where it belongs [`#63`](https://github.com/minimistjs/minimist/pull/63)
+
+### Commits
+
+- add test [`6be5dae`](https://github.com/minimistjs/minimist/commit/6be5dae35a32a987bcf4137fcd6c19c5200ee909)
+- fix bad boolean regexp [`ac3fc79`](https://github.com/minimistjs/minimist/commit/ac3fc796e63b95128fdbdf67ea7fad71bd59aa76)
+
+## [v1.2.0](https://github.com/minimistjs/minimist/compare/v1.1.3...v1.2.0) - 2015-08-24
+
+### Commits
+
+- failing -k=v short test [`63416b8`](https://github.com/minimistjs/minimist/commit/63416b8cd1d0d70e4714564cce465a36e4dd26d7)
+- kv short fix [`6bbe145`](https://github.com/minimistjs/minimist/commit/6bbe14529166245e86424f220a2321442fe88dc3)
+- failing kv short test [`f72ab7f`](https://github.com/minimistjs/minimist/commit/f72ab7f4572adc52902c9b6873cc969192f01b10)
+- fixed kv test [`f5a48c3`](https://github.com/minimistjs/minimist/commit/f5a48c3e50e40ca54f00c8e84de4b4d6e9897fa8)
+- enforce space between arg key and value [`86b321a`](https://github.com/minimistjs/minimist/commit/86b321affe648a8e016c095a4f0efa9d9074f502)
+
+## [v1.1.3](https://github.com/minimistjs/minimist/compare/v1.1.2...v1.1.3) - 2015-08-06
+
+### Commits
+
+- add failing test - boolean alias array [`0fa3c5b`](https://github.com/minimistjs/minimist/commit/0fa3c5b3dd98551ddecf5392831b4c21211743fc)
+- fix boolean values with multiple aliases [`9c0a6e7`](https://github.com/minimistjs/minimist/commit/9c0a6e7de25a273b11bbf9a7464f0bd833779795)
+
+## [v1.1.2](https://github.com/minimistjs/minimist/compare/v1.1.1...v1.1.2) - 2015-07-22
+
+### Commits
+
+- Convert boolean arguments to boolean values [`8f3dc27`](https://github.com/minimistjs/minimist/commit/8f3dc27cf833f1d54671b6d0bcb55c2fe19672a9)
+- use non-ancient npm, node 0.12 and iojs [`61ed1d0`](https://github.com/minimistjs/minimist/commit/61ed1d034b9ec7282764ce76f3992b1a0b4906ae)
+- an older npm for 0.8 [`25cf778`](https://github.com/minimistjs/minimist/commit/25cf778b1220e7838a526832ad6972f75244054f)
+
+## [v1.1.1](https://github.com/minimistjs/minimist/compare/v1.1.0...v1.1.1) - 2015-03-10
+
+### Commits
+
+- check that they type of a value is a boolean, not just that it is currently set to a boolean [`6863198`](https://github.com/minimistjs/minimist/commit/6863198e36139830ff1f20ffdceaddd93f2c1db9)
+- upgrade tape, fix type issues from old tape version [`806712d`](https://github.com/minimistjs/minimist/commit/806712df91604ed02b8e39aa372b84aea659ee34)
+- test for setting a boolean to a null default [`8c444fe`](https://github.com/minimistjs/minimist/commit/8c444fe89384ded7d441c120915ea60620b01dd3)
+- if the previous value was a boolean, without an default (or with an alias) don't make an array either [`e5f419a`](https://github.com/minimistjs/minimist/commit/e5f419a3b5b3bc3f9e5ac71b7040621af70ed2dd)
+
+## [v1.1.0](https://github.com/minimistjs/minimist/compare/v1.0.0...v1.1.0) - 2014-08-10
+
+### Commits
+
+- add support for handling "unknown" options not registered with the parser. [`6f3cc5d`](https://github.com/minimistjs/minimist/commit/6f3cc5d4e84524932a6ef2ce3592acc67cdd4383)
+- reformat package.json [`02ed371`](https://github.com/minimistjs/minimist/commit/02ed37115194d3697ff358e8e25e5e66bab1d9f8)
+- coverage script [`e5531ba`](https://github.com/minimistjs/minimist/commit/e5531ba0479da3b8138d3d8cac545d84ccb1c8df)
+- extra fn to get 100% coverage again [`a6972da`](https://github.com/minimistjs/minimist/commit/a6972da89e56bf77642f8ec05a13b6558db93498)
+
+## [v1.0.0](https://github.com/minimistjs/minimist/compare/v0.2.3...v1.0.0) - 2014-08-10
+
+### Commits
+
+- added stopEarly option [`471c7e4`](https://github.com/minimistjs/minimist/commit/471c7e4a7e910fc7ad8f9df850a186daf32c64e9)
+- fix list [`fef6ae7`](https://github.com/minimistjs/minimist/commit/fef6ae79c38b9dc1c49569abb7cd04eb965eac5e)
+
+## [v0.2.3](https://github.com/minimistjs/minimist/compare/v0.2.2...v0.2.3) - 2023-02-09
+
+### Merged
+
+- [Fix] Fix long option followed by single dash [`#17`](https://github.com/minimistjs/minimist/pull/17)
+- [Tests] Remove duplicate test [`#12`](https://github.com/minimistjs/minimist/pull/12)
+- [Fix] opt.string works with multiple aliases [`#10`](https://github.com/minimistjs/minimist/pull/10)
+
+### Fixed
+
+- [Fix] Fix long option followed by single dash (#17) [`#15`](https://github.com/minimistjs/minimist/issues/15)
+- [Tests] Remove duplicate test (#12) [`#8`](https://github.com/minimistjs/minimist/issues/8)
+- [Fix] opt.string works with multiple aliases (#10) [`#9`](https://github.com/minimistjs/minimist/issues/9)
+
+### Commits
+
+- [eslint] fix indentation and whitespace [`e5f5067`](https://github.com/minimistjs/minimist/commit/e5f5067259ceeaf0b098d14bec910f87e58708c7)
+- [eslint] more cleanup [`36ac5d0`](https://github.com/minimistjs/minimist/commit/36ac5d0d95e4947d074e5737d94814034ca335d1)
+- [eslint] fix indentation [`34b0f1c`](https://github.com/minimistjs/minimist/commit/34b0f1ccaa45183c3c4f06a91f9b405180a6f982)
+- isConstructorOrProto adapted from PR [`ef9153f`](https://github.com/minimistjs/minimist/commit/ef9153fc52b6cea0744b2239921c5dcae4697f11)
+- [Dev Deps] update `@ljharb/eslint-config`, `aud` [`098873c`](https://github.com/minimistjs/minimist/commit/098873c213cdb7c92e55ae1ef5aa1af3a8192a79)
+- [Dev Deps] add missing `npmignore` dev dep [`3226afa`](https://github.com/minimistjs/minimist/commit/3226afaf09e9d127ca369742437fe6e88f752d6b)
+
+## [v0.2.2](https://github.com/minimistjs/minimist/compare/v0.2.1...v0.2.2) - 2022-10-10
+
+### Commits
+
+- [meta] add `auto-changelog` [`73923d2`](https://github.com/minimistjs/minimist/commit/73923d223553fca08b1ba77e3fbc2a492862ae4c)
+- [actions] add reusable workflows [`d80727d`](https://github.com/minimistjs/minimist/commit/d80727df77bfa9e631044d7f16368d8f09242c91)
+- [eslint] add eslint; rules to enable later are warnings [`48bc06a`](https://github.com/minimistjs/minimist/commit/48bc06a1b41f00e9cdf183db34f7a51ba70e98d4)
+- [readme] rename and add badges [`5df0fe4`](https://github.com/minimistjs/minimist/commit/5df0fe49211bd09a3636f8686a7cb3012c3e98f0)
+- [Dev Deps] switch from `covert` to `nyc` [`a48b128`](https://github.com/minimistjs/minimist/commit/a48b128fdb8d427dfb20a15273f83e38d97bef07)
+- [Dev Deps] update `covert`, `tape`; remove unnecessary `tap` [`f0fb958`](https://github.com/minimistjs/minimist/commit/f0fb958e9a1fe980cdffc436a211b0bda58f621b)
+- [meta] create FUNDING.yml; add `funding` in package.json [`3639e0c`](https://github.com/minimistjs/minimist/commit/3639e0c819359a366387e425ab6eabf4c78d3caa)
+- [meta] use `npmignore` to autogenerate an npmignore file [`be2e038`](https://github.com/minimistjs/minimist/commit/be2e038c342d8333b32f0fde67a0026b79c8150e)
+- Only apps should have lockfiles [`282b570`](https://github.com/minimistjs/minimist/commit/282b570e7489d01b03f2d6d3dabf79cd3e5f84cf)
+- [meta] add `safe-publish-latest` [`4b927de`](https://github.com/minimistjs/minimist/commit/4b927de696d561c636b4f43bf49d4597cb36d6d6)
+- [Tests] add `aud` in `posttest` [`b32d9bd`](https://github.com/minimistjs/minimist/commit/b32d9bd0ab340f4e9f8c3a97ff2a4424f25fab8c)
+- [meta] update repo URLs [`f9fdfc0`](https://github.com/minimistjs/minimist/commit/f9fdfc032c54884d9a9996a390c63cd0719bbe1a)
+
+## [v0.2.1](https://github.com/minimistjs/minimist/compare/v0.2.0...v0.2.1) - 2020-03-12
+
+## [v0.2.0](https://github.com/minimistjs/minimist/compare/v0.1.0...v0.2.0) - 2014-06-19
+
+### Commits
+
+- support all-boolean mode [`450a97f`](https://github.com/minimistjs/minimist/commit/450a97f6e2bc85c7a4a13185c19a818d9a5ebe69)
+
+## [v0.1.0](https://github.com/minimistjs/minimist/compare/v0.0.10...v0.1.0) - 2014-05-12
+
+### Commits
+
+- Provide a mechanism to segregate -- arguments [`ce4a1e6`](https://github.com/minimistjs/minimist/commit/ce4a1e63a7e8d5ab88d2a3768adefa6af98a445a)
+- documented argv['--'] [`14db0e6`](https://github.com/minimistjs/minimist/commit/14db0e6dbc6d2b9e472adaa54dad7004b364634f)
+- Adding a test-case for notFlags segregation [`715c1e3`](https://github.com/minimistjs/minimist/commit/715c1e3714be223f998f6c537af6b505f0236c16)
+
+## [v0.0.10](https://github.com/minimistjs/minimist/compare/v0.0.9...v0.0.10) - 2014-05-11
+
+### Commits
+
+- dedicated boolean test [`46e448f`](https://github.com/minimistjs/minimist/commit/46e448f9f513cfeb2bcc8b688b9b47ba1e515c2b)
+- dedicated num test [`9bf2d36`](https://github.com/minimistjs/minimist/commit/9bf2d36f1d3b8795be90b8f7de0a937f098aa394)
+- aliased values treated as strings [`1ab743b`](https://github.com/minimistjs/minimist/commit/1ab743bad4484d69f1259bed42f9531de01119de)
+- cover the case of already numbers, at 100% coverage [`b2bb044`](https://github.com/minimistjs/minimist/commit/b2bb04436599d77a2ce029e8e555e25b3aa55d13)
+- another test for higher coverage [`3662624`](https://github.com/minimistjs/minimist/commit/3662624be976d5489d486a856849c048d13be903)
+
+## [v0.0.9](https://github.com/minimistjs/minimist/compare/v0.0.8...v0.0.9) - 2014-05-08
+
+### Commits
+
+- Eliminate `longest` fn. [`824f642`](https://github.com/minimistjs/minimist/commit/824f642038d1b02ede68b6261d1d65163390929a)
+
+## [v0.0.8](https://github.com/minimistjs/minimist/compare/v0.0.7...v0.0.8) - 2014-02-20
+
+### Commits
+
+- return '' if flag is string and empty [`fa63ed4`](https://github.com/minimistjs/minimist/commit/fa63ed4651a4ef4eefddce34188e0d98d745a263)
+- handle joined single letters [`66c248f`](https://github.com/minimistjs/minimist/commit/66c248f0241d4d421d193b022e9e365f11178534)
+
+## [v0.0.7](https://github.com/minimistjs/minimist/compare/v0.0.6...v0.0.7) - 2014-02-08
+
+### Commits
+
+- another swap of .test for .match [`d1da408`](https://github.com/minimistjs/minimist/commit/d1da40819acbe846d89a5c02721211e3c1260dde)
+
+## [v0.0.6](https://github.com/minimistjs/minimist/compare/v0.0.5...v0.0.6) - 2014-02-08
+
+### Commits
+
+- use .test() instead of .match() to not crash on non-string values in the arguments array [`7e0d1ad`](https://github.com/minimistjs/minimist/commit/7e0d1add8c9e5b9b20a4d3d0f9a94d824c578da1)
+
+## [v0.0.5](https://github.com/minimistjs/minimist/compare/v0.0.4...v0.0.5) - 2013-09-18
+
+### Commits
+
+- Improve '--' handling. [`b11822c`](https://github.com/minimistjs/minimist/commit/b11822c09cc9d2460f30384d12afc0b953c037a4)
+
+## [v0.0.4](https://github.com/minimistjs/minimist/compare/v0.0.3...v0.0.4) - 2013-09-17
+
+## [v0.0.3](https://github.com/minimistjs/minimist/compare/v0.0.2...v0.0.3) - 2013-09-12
+
+### Commits
+
+- failing test for single dash preceeding a double dash [`b465514`](https://github.com/minimistjs/minimist/commit/b465514b82c9ae28972d714facd951deb2ad762b)
+- fix for the dot test [`6a095f1`](https://github.com/minimistjs/minimist/commit/6a095f1d364c8fab2d6753d2291a0649315d297a)
+
+## [v0.0.2](https://github.com/minimistjs/minimist/compare/v0.0.1...v0.0.2) - 2013-08-28
+
+### Commits
+
+- allow dotted aliases & defaults [`321c33e`](https://github.com/minimistjs/minimist/commit/321c33e755485faaeb44eeb1c05d33b2e0a5a7c4)
+- use a better version of ff [`e40f611`](https://github.com/minimistjs/minimist/commit/e40f61114cf7be6f7947f7b3eed345853a67dbbb)
+
+## [v0.0.1](https://github.com/minimistjs/minimist/compare/v0.0.0...v0.0.1) - 2013-06-25
+
+### Commits
+
+- remove trailing commas [`6ff0fa0`](https://github.com/minimistjs/minimist/commit/6ff0fa055064f15dbe06d50b89d5173a6796e1db)
+
+## v0.0.0 - 2013-06-25
+
+### Commits
+
+- half of the parse test ported [`3079326`](https://github.com/minimistjs/minimist/commit/307932601325087de6cf94188eb798ffc4f3088a)
+- stripped down code and a passing test from optimist [`7cced88`](https://github.com/minimistjs/minimist/commit/7cced88d82e399d1a03ed23eb667f04d3f320d10)
+- ported parse tests completely over [`9448754`](https://github.com/minimistjs/minimist/commit/944875452e0820df6830b1408c26a0f7d3e1db04)
+- docs, package.json [`a5bf46a`](https://github.com/minimistjs/minimist/commit/a5bf46ac9bb3bd114a9c340276c62c1091e538d5)
+- move more short tests into short.js [`503edb5`](https://github.com/minimistjs/minimist/commit/503edb5c41d89c0d40831ee517154fc13b0f18b9)
+- default bool test was wrong, not the code [`1b9f5db`](https://github.com/minimistjs/minimist/commit/1b9f5db4741b49962846081b68518de824992097)
+- passing long tests ripped out of parse.js [`7972c4a`](https://github.com/minimistjs/minimist/commit/7972c4aff1f4803079e1668006658e2a761a0428)
+- badges [`84c0370`](https://github.com/minimistjs/minimist/commit/84c037063664d42878aace715fe6572ce01b6f3b)
+- all the tests now ported, some failures [`64239ed`](https://github.com/minimistjs/minimist/commit/64239edfe92c711c4eb0da254fcdfad2a5fdb605)
+- failing short test [`f8a5341`](https://github.com/minimistjs/minimist/commit/f8a534112dd1138d2fad722def56a848480c446f)
+- fixed the numeric test [`6b034f3`](https://github.com/minimistjs/minimist/commit/6b034f37c79342c60083ed97fd222e16928aac51)

+ 18 - 0
node_modules/minimist/LICENSE

@@ -0,0 +1,18 @@
+This software is released under the MIT license:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 121 - 0
node_modules/minimist/README.md

@@ -0,0 +1,121 @@
+# minimist <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
+
+[![github actions][actions-image]][actions-url]
+[![coverage][codecov-image]][codecov-url]
+[![License][license-image]][license-url]
+[![Downloads][downloads-image]][downloads-url]
+
+[![npm badge][npm-badge-png]][package-url]
+
+parse argument options
+
+This module is the guts of optimist's argument parser without all the
+fanciful decoration.
+
+# example
+
+``` js
+var argv = require('minimist')(process.argv.slice(2));
+console.log(argv);
+```
+
+```
+$ node example/parse.js -a beep -b boop
+{ _: [], a: 'beep', b: 'boop' }
+```
+
+```
+$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
+{
+	_: ['foo', 'bar', 'baz'],
+	x: 3,
+	y: 4,
+	n: 5,
+	a: true,
+	b: true,
+	c: true,
+	beep: 'boop'
+}
+```
+
+# security
+
+Previous versions had a prototype pollution bug that could cause privilege
+escalation in some circumstances when handling untrusted user input.
+
+Please use version 1.2.6 or later:
+
+* https://security.snyk.io/vuln/SNYK-JS-MINIMIST-2429795 (version <=1.2.5)
+* https://snyk.io/vuln/SNYK-JS-MINIMIST-559764 (version <=1.2.3)
+
+# methods
+
+``` js
+var parseArgs = require('minimist')
+```
+
+## var argv = parseArgs(args, opts={})
+
+Return an argument object `argv` populated with the array arguments from `args`.
+
+`argv._` contains all the arguments that didn't have an option associated with
+them.
+
+Numeric-looking arguments will be returned as numbers unless `opts.string` or
+`opts.boolean` is set for that argument name.
+
+Any arguments after `'--'` will not be parsed and will end up in `argv._`.
+
+options can be:
+
+* `opts.string` - a string or array of strings argument names to always treat as
+strings
+* `opts.boolean` - a boolean, string or array of strings to always treat as
+booleans. if `true` will treat all double hyphenated arguments without equal signs
+as boolean (e.g. affects `--foo`, not `-f` or `--foo=bar`)
+* `opts.alias` - an object mapping string names to strings or arrays of string
+argument names to use as aliases
+* `opts.default` - an object mapping string argument names to default values
+* `opts.stopEarly` - when true, populate `argv._` with everything after the
+first non-option
+* `opts['--']` - when true, populate `argv._` with everything before the `--`
+and `argv['--']` with everything after the `--`. Here's an example:
+
+  ```
+  > require('./')('one two three -- four five --six'.split(' '), { '--': true })
+  {
+    _: ['one', 'two', 'three'],
+    '--': ['four', 'five', '--six']
+  }
+  ```
+
+  Note that with `opts['--']` set, parsing for arguments still stops after the
+  `--`.
+
+* `opts.unknown` - a function which is invoked with a command line parameter not
+defined in the `opts` configuration object. If the function returns `false`, the
+unknown option is not added to `argv`.
+
+# install
+
+With [npm](https://npmjs.org) do:
+
+```
+npm install minimist
+```
+
+# license
+
+MIT
+
+[package-url]: https://npmjs.org/package/minimist
+[npm-version-svg]: https://versionbadg.es/minimistjs/minimist.svg
+[npm-badge-png]: https://nodei.co/npm/minimist.png?downloads=true&stars=true
+[license-image]: https://img.shields.io/npm/l/minimist.svg
+[license-url]: LICENSE
+[downloads-image]: https://img.shields.io/npm/dm/minimist.svg
+[downloads-url]: https://npm-stat.com/charts.html?package=minimist
+[codecov-image]: https://codecov.io/gh/minimistjs/minimist/branch/main/graphs/badge.svg
+[codecov-url]: https://app.codecov.io/gh/minimistjs/minimist/
+[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/minimistjs/minimist
+[actions-url]: https://github.com/minimistjs/minimist/actions

+ 4 - 0
node_modules/minimist/example/parse.js

@@ -0,0 +1,4 @@
+'use strict';
+
+var argv = require('../')(process.argv.slice(2));
+console.log(argv);

+ 263 - 0
node_modules/minimist/index.js

@@ -0,0 +1,263 @@
+'use strict';
+
+function hasKey(obj, keys) {
+	var o = obj;
+	keys.slice(0, -1).forEach(function (key) {
+		o = o[key] || {};
+	});
+
+	var key = keys[keys.length - 1];
+	return key in o;
+}
+
+function isNumber(x) {
+	if (typeof x === 'number') { return true; }
+	if ((/^0x[0-9a-f]+$/i).test(x)) { return true; }
+	return (/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/).test(x);
+}
+
+function isConstructorOrProto(obj, key) {
+	return (key === 'constructor' && typeof obj[key] === 'function') || key === '__proto__';
+}
+
+module.exports = function (args, opts) {
+	if (!opts) { opts = {}; }
+
+	var flags = {
+		bools: {},
+		strings: {},
+		unknownFn: null,
+	};
+
+	if (typeof opts.unknown === 'function') {
+		flags.unknownFn = opts.unknown;
+	}
+
+	if (typeof opts.boolean === 'boolean' && opts.boolean) {
+		flags.allBools = true;
+	} else {
+		[].concat(opts.boolean).filter(Boolean).forEach(function (key) {
+			flags.bools[key] = true;
+		});
+	}
+
+	var aliases = {};
+
+	function aliasIsBoolean(key) {
+		return aliases[key].some(function (x) {
+			return flags.bools[x];
+		});
+	}
+
+	Object.keys(opts.alias || {}).forEach(function (key) {
+		aliases[key] = [].concat(opts.alias[key]);
+		aliases[key].forEach(function (x) {
+			aliases[x] = [key].concat(aliases[key].filter(function (y) {
+				return x !== y;
+			}));
+		});
+	});
+
+	[].concat(opts.string).filter(Boolean).forEach(function (key) {
+		flags.strings[key] = true;
+		if (aliases[key]) {
+			[].concat(aliases[key]).forEach(function (k) {
+				flags.strings[k] = true;
+			});
+		}
+	});
+
+	var defaults = opts.default || {};
+
+	var argv = { _: [] };
+
+	function argDefined(key, arg) {
+		return (flags.allBools && (/^--[^=]+$/).test(arg))
+			|| flags.strings[key]
+			|| flags.bools[key]
+			|| aliases[key];
+	}
+
+	function setKey(obj, keys, value) {
+		var o = obj;
+		for (var i = 0; i < keys.length - 1; i++) {
+			var key = keys[i];
+			if (isConstructorOrProto(o, key)) { return; }
+			if (o[key] === undefined) { o[key] = {}; }
+			if (
+				o[key] === Object.prototype
+				|| o[key] === Number.prototype
+				|| o[key] === String.prototype
+			) {
+				o[key] = {};
+			}
+			if (o[key] === Array.prototype) { o[key] = []; }
+			o = o[key];
+		}
+
+		var lastKey = keys[keys.length - 1];
+		if (isConstructorOrProto(o, lastKey)) { return; }
+		if (
+			o === Object.prototype
+			|| o === Number.prototype
+			|| o === String.prototype
+		) {
+			o = {};
+		}
+		if (o === Array.prototype) { o = []; }
+		if (o[lastKey] === undefined || flags.bools[lastKey] || typeof o[lastKey] === 'boolean') {
+			o[lastKey] = value;
+		} else if (Array.isArray(o[lastKey])) {
+			o[lastKey].push(value);
+		} else {
+			o[lastKey] = [o[lastKey], value];
+		}
+	}
+
+	function setArg(key, val, arg) {
+		if (arg && flags.unknownFn && !argDefined(key, arg)) {
+			if (flags.unknownFn(arg) === false) { return; }
+		}
+
+		var value = !flags.strings[key] && isNumber(val)
+			? Number(val)
+			: val;
+		setKey(argv, key.split('.'), value);
+
+		(aliases[key] || []).forEach(function (x) {
+			setKey(argv, x.split('.'), value);
+		});
+	}
+
+	Object.keys(flags.bools).forEach(function (key) {
+		setArg(key, defaults[key] === undefined ? false : defaults[key]);
+	});
+
+	var notFlags = [];
+
+	if (args.indexOf('--') !== -1) {
+		notFlags = args.slice(args.indexOf('--') + 1);
+		args = args.slice(0, args.indexOf('--'));
+	}
+
+	for (var i = 0; i < args.length; i++) {
+		var arg = args[i];
+		var key;
+		var next;
+
+		if ((/^--.+=/).test(arg)) {
+			// Using [\s\S] instead of . because js doesn't support the
+			// 'dotall' regex modifier. See:
+			// http://stackoverflow.com/a/1068308/13216
+			var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
+			key = m[1];
+			var value = m[2];
+			if (flags.bools[key]) {
+				value = value !== 'false';
+			}
+			setArg(key, value, arg);
+		} else if ((/^--no-.+/).test(arg)) {
+			key = arg.match(/^--no-(.+)/)[1];
+			setArg(key, false, arg);
+		} else if ((/^--.+/).test(arg)) {
+			key = arg.match(/^--(.+)/)[1];
+			next = args[i + 1];
+			if (
+				next !== undefined
+				&& !(/^(-|--)[^-]/).test(next)
+				&& !flags.bools[key]
+				&& !flags.allBools
+				&& (aliases[key] ? !aliasIsBoolean(key) : true)
+			) {
+				setArg(key, next, arg);
+				i += 1;
+			} else if ((/^(true|false)$/).test(next)) {
+				setArg(key, next === 'true', arg);
+				i += 1;
+			} else {
+				setArg(key, flags.strings[key] ? '' : true, arg);
+			}
+		} else if ((/^-[^-]+/).test(arg)) {
+			var letters = arg.slice(1, -1).split('');
+
+			var broken = false;
+			for (var j = 0; j < letters.length; j++) {
+				next = arg.slice(j + 2);
+
+				if (next === '-') {
+					setArg(letters[j], next, arg);
+					continue;
+				}
+
+				if ((/[A-Za-z]/).test(letters[j]) && next[0] === '=') {
+					setArg(letters[j], next.slice(1), arg);
+					broken = true;
+					break;
+				}
+
+				if (
+					(/[A-Za-z]/).test(letters[j])
+					&& (/-?\d+(\.\d*)?(e-?\d+)?$/).test(next)
+				) {
+					setArg(letters[j], next, arg);
+					broken = true;
+					break;
+				}
+
+				if (letters[j + 1] && letters[j + 1].match(/\W/)) {
+					setArg(letters[j], arg.slice(j + 2), arg);
+					broken = true;
+					break;
+				} else {
+					setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg);
+				}
+			}
+
+			key = arg.slice(-1)[0];
+			if (!broken && key !== '-') {
+				if (
+					args[i + 1]
+					&& !(/^(-|--)[^-]/).test(args[i + 1])
+					&& !flags.bools[key]
+					&& (aliases[key] ? !aliasIsBoolean(key) : true)
+				) {
+					setArg(key, args[i + 1], arg);
+					i += 1;
+				} else if (args[i + 1] && (/^(true|false)$/).test(args[i + 1])) {
+					setArg(key, args[i + 1] === 'true', arg);
+					i += 1;
+				} else {
+					setArg(key, flags.strings[key] ? '' : true, arg);
+				}
+			}
+		} else {
+			if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
+				argv._.push(flags.strings._ || !isNumber(arg) ? arg : Number(arg));
+			}
+			if (opts.stopEarly) {
+				argv._.push.apply(argv._, args.slice(i + 1));
+				break;
+			}
+		}
+	}
+
+	Object.keys(defaults).forEach(function (k) {
+		if (!hasKey(argv, k.split('.'))) {
+			setKey(argv, k.split('.'), defaults[k]);
+
+			(aliases[k] || []).forEach(function (x) {
+				setKey(argv, x.split('.'), defaults[k]);
+			});
+		}
+	});
+
+	if (opts['--']) {
+		argv['--'] = notFlags.slice();
+	} else {
+		notFlags.forEach(function (k) {
+			argv._.push(k);
+		});
+	}
+
+	return argv;
+};

+ 75 - 0
node_modules/minimist/package.json

@@ -0,0 +1,75 @@
+{
+	"name": "minimist",
+	"version": "1.2.8",
+	"description": "parse argument options",
+	"main": "index.js",
+	"devDependencies": {
+		"@ljharb/eslint-config": "^21.0.1",
+		"aud": "^2.0.2",
+		"auto-changelog": "^2.4.0",
+		"eslint": "=8.8.0",
+		"in-publish": "^2.0.1",
+		"npmignore": "^0.3.0",
+		"nyc": "^10.3.2",
+		"safe-publish-latest": "^2.0.0",
+		"tape": "^5.6.3"
+	},
+	"scripts": {
+		"prepack": "npmignore --auto --commentLines=auto",
+		"prepublishOnly": "safe-publish-latest",
+		"prepublish": "not-in-publish || npm run prepublishOnly",
+		"lint": "eslint --ext=js,mjs .",
+		"pretest": "npm run lint",
+		"tests-only": "nyc tape 'test/**/*.js'",
+		"test": "npm run tests-only",
+		"posttest": "aud --production",
+		"version": "auto-changelog && git add CHANGELOG.md",
+		"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
+	},
+	"testling": {
+		"files": "test/*.js",
+		"browsers": [
+			"ie/6..latest",
+			"ff/5",
+			"firefox/latest",
+			"chrome/10",
+			"chrome/latest",
+			"safari/5.1",
+			"safari/latest",
+			"opera/12"
+		]
+	},
+	"repository": {
+		"type": "git",
+		"url": "git://github.com/minimistjs/minimist.git"
+	},
+	"homepage": "https://github.com/minimistjs/minimist",
+	"keywords": [
+		"argv",
+		"getopt",
+		"parser",
+		"optimist"
+	],
+	"author": {
+		"name": "James Halliday",
+		"email": "mail@substack.net",
+		"url": "http://substack.net"
+	},
+	"funding": {
+		"url": "https://github.com/sponsors/ljharb"
+	},
+	"license": "MIT",
+	"auto-changelog": {
+		"output": "CHANGELOG.md",
+		"template": "keepachangelog",
+		"unreleased": false,
+		"commitLimit": false,
+		"backfillLimit": false,
+		"hideCredit": true
+	},
+	"publishConfig": {
+		"ignore": [
+			".github/workflows"
+		]
+	}
+}

+ 34 - 0
node_modules/minimist/test/all_bool.js

@@ -0,0 +1,34 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('flag boolean true (default all --args to boolean)', function (t) {
+	var argv = parse(['moo', '--honk', 'cow'], {
+		boolean: true,
+	});
+
+	t.deepEqual(argv, {
+		honk: true,
+		_: ['moo', 'cow'],
+	});
+
+	t.deepEqual(typeof argv.honk, 'boolean');
+	t.end();
+});
+
+test('flag boolean true only affects double hyphen arguments without equals signs', function (t) {
+	var argv = parse(['moo', '--honk', 'cow', '-p', '55', '--tacos=good'], {
+		boolean: true,
+	});
+
+	t.deepEqual(argv, {
+		honk: true,
+		tacos: 'good',
+		p: 55,
+		_: ['moo', 'cow'],
+	});
+
+	t.deepEqual(typeof argv.honk, 'boolean');
+	t.end();
+});

+ 177 - 0
node_modules/minimist/test/bool.js

@@ -0,0 +1,177 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('flag boolean default false', function (t) {
+	var argv = parse(['moo'], {
+		boolean: ['t', 'verbose'],
+		default: { verbose: false, t: false },
+	});
+
+	t.deepEqual(argv, {
+		verbose: false,
+		t: false,
+		_: ['moo'],
+	});
+
+	t.deepEqual(typeof argv.verbose, 'boolean');
+	t.deepEqual(typeof argv.t, 'boolean');
+	t.end();
+
+});
+
+test('boolean groups', function (t) {
+	var argv = parse(['-x', '-z', 'one', 'two', 'three'], {
+		boolean: ['x', 'y', 'z'],
+	});
+
+	t.deepEqual(argv, {
+		x: true,
+		y: false,
+		z: true,
+		_: ['one', 'two', 'three'],
+	});
+
+	t.deepEqual(typeof argv.x, 'boolean');
+	t.deepEqual(typeof argv.y, 'boolean');
+	t.deepEqual(typeof argv.z, 'boolean');
+	t.end();
+});
+test('boolean and alias with chainable api', function (t) {
+	var aliased = ['-h', 'derp'];
+	var regular = ['--herp', 'derp'];
+	var aliasedArgv = parse(aliased, {
+		boolean: 'herp',
+		alias: { h: 'herp' },
+	});
+	var propertyArgv = parse(regular, {
+		boolean: 'herp',
+		alias: { h: 'herp' },
+	});
+	var expected = {
+		herp: true,
+		h: true,
+		_: ['derp'],
+	};
+
+	t.same(aliasedArgv, expected);
+	t.same(propertyArgv, expected);
+	t.end();
+});
+
+test('boolean and alias with options hash', function (t) {
+	var aliased = ['-h', 'derp'];
+	var regular = ['--herp', 'derp'];
+	var opts = {
+		alias: { h: 'herp' },
+		boolean: 'herp',
+	};
+	var aliasedArgv = parse(aliased, opts);
+	var propertyArgv = parse(regular, opts);
+	var expected = {
+		herp: true,
+		h: true,
+		_: ['derp'],
+	};
+	t.same(aliasedArgv, expected);
+	t.same(propertyArgv, expected);
+	t.end();
+});
+
+test('boolean and alias array with options hash', function (t) {
+	var aliased = ['-h', 'derp'];
+	var regular = ['--herp', 'derp'];
+	var alt = ['--harp', 'derp'];
+	var opts = {
+		alias: { h: ['herp', 'harp'] },
+		boolean: 'h',
+	};
+	var aliasedArgv = parse(aliased, opts);
+	var propertyArgv = parse(regular, opts);
+	var altPropertyArgv = parse(alt, opts);
+	var expected = {
+		harp: true,
+		herp: true,
+		h: true,
+		_: ['derp'],
+	};
+	t.same(aliasedArgv, expected);
+	t.same(propertyArgv, expected);
+	t.same(altPropertyArgv, expected);
+	t.end();
+});
+
+test('boolean and alias using explicit true', function (t) {
+	var aliased = ['-h', 'true'];
+	var regular = ['--herp', 'true'];
+	var opts = {
+		alias: { h: 'herp' },
+		boolean: 'h',
+	};
+	var aliasedArgv = parse(aliased, opts);
+	var propertyArgv = parse(regular, opts);
+	var expected = {
+		herp: true,
+		h: true,
+		_: [],
+	};
+
+	t.same(aliasedArgv, expected);
+	t.same(propertyArgv, expected);
+	t.end();
+});
+
+// regression, see https://github.com/substack/node-optimist/issues/71
+test('boolean and --x=true', function (t) {
+	var parsed = parse(['--boool', '--other=true'], {
+		boolean: 'boool',
+	});
+
+	t.same(parsed.boool, true);
+	t.same(parsed.other, 'true');
+
+	parsed = parse(['--boool', '--other=false'], {
+		boolean: 'boool',
+	});
+
+	t.same(parsed.boool, true);
+	t.same(parsed.other, 'false');
+	t.end();
+});
+
+test('boolean --boool=true', function (t) {
+	var parsed = parse(['--boool=true'], {
+		default: {
+			boool: false,
+		},
+		boolean: ['boool'],
+	});
+
+	t.same(parsed.boool, true);
+	t.end();
+});
+
+test('boolean --boool=false', function (t) {
+	var parsed = parse(['--boool=false'], {
+		default: {
+			boool: true,
+		},
+		boolean: ['boool'],
+	});
+
+	t.same(parsed.boool, false);
+	t.end();
+});
+
+test('boolean using something similar to true', function (t) {
+	var opts = { boolean: 'h' };
+	var result = parse(['-h', 'true.txt'], opts);
+	var expected = {
+		h: true,
+		_: ['true.txt'],
+	};
+
+	t.same(result, expected);
+	t.end();
+});

+ 43 - 0
node_modules/minimist/test/dash.js

@@ -0,0 +1,43 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('-', function (t) {
+	t.plan(6);
+	t.deepEqual(parse(['-n', '-']), { n: '-', _: [] });
+	t.deepEqual(parse(['--nnn', '-']), { nnn: '-', _: [] });
+	t.deepEqual(parse(['-']), { _: ['-'] });
+	t.deepEqual(parse(['-f-']), { f: '-', _: [] });
+	t.deepEqual(
+		parse(['-b', '-'], { boolean: 'b' }),
+		{ b: true, _: ['-'] }
+	);
+	t.deepEqual(
+		parse(['-s', '-'], { string: 's' }),
+		{ s: '-', _: [] }
+	);
+});
+
+test('-a -- b', function (t) {
+	t.plan(2);
+	t.deepEqual(parse(['-a', '--', 'b']), { a: true, _: ['b'] });
+	t.deepEqual(parse(['--a', '--', 'b']), { a: true, _: ['b'] });
+});
+
+test('move arguments after the -- into their own `--` array', function (t) {
+	t.plan(1);
+	t.deepEqual(
+		parse(['--name', 'John', 'before', '--', 'after'], { '--': true }),
+		{ name: 'John', _: ['before'], '--': ['after'] }
+	);
+});
+
+test('--- option value', function (t) {
+	// A multi-dash value is largely an edge case, but check the behaviour is as expected,
+	// and in particular the same for short option and long option (as made consistent in Jan 2023).
+	t.plan(2);
+	t.deepEqual(parse(['-n', '---']), { n: '---', _: [] });
+	t.deepEqual(parse(['--nnn', '---']), { nnn: '---', _: [] });
+});
+

+ 37 - 0
node_modules/minimist/test/default_bool.js

@@ -0,0 +1,37 @@
+'use strict';
+
+var test = require('tape');
+var parse = require('../');
+
+test('boolean default true', function (t) {
+	var argv = parse([], {
+		boolean: 'sometrue',
+		default: { sometrue: true },
+	});
+	t.equal(argv.sometrue, true);
+	t.end();
+});
+
+test('boolean default false', function (t) {
+	var argv = parse([], {
+		boolean: 'somefalse',
+		default: { somefalse: false },
+	});
+	t.equal(argv.somefalse, false);
+	t.end();
+});
+
+test('boolean default to null', function (t) {
+	var argv = parse([], {
+		boolean: 'maybe',
+		default: { maybe: null },
+	});
+	t.equal(argv.maybe, null);
+
+	var argvLong = parse(['--maybe'], {
+		boolean: 'maybe',
+		default: { maybe: null },
+	});
+	t.equal(argvLong.maybe, true);
+	t.end();
+});

+ 24 - 0
node_modules/minimist/test/dotted.js

@@ -0,0 +1,24 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('dotted alias', function (t) {
+	var argv = parse(['--a.b', '22'], { default: { 'a.b': 11 }, alias: { 'a.b': 'aa.bb' } });
+	t.equal(argv.a.b, 22);
+	t.equal(argv.aa.bb, 22);
+	t.end();
+});
+
+test('dotted default', function (t) {
+	var argv = parse('', { default: { 'a.b': 11 }, alias: { 'a.b': 'aa.bb' } });
+	t.equal(argv.a.b, 11);
+	t.equal(argv.aa.bb, 11);
+	t.end();
+});
+
+test('dotted default with no alias', function (t) {
+	var argv = parse('', { default: { 'a.b': 11 } });
+	t.equal(argv.a.b, 11);
+	t.end();
+});

+ 32 - 0
node_modules/minimist/test/kv_short.js

@@ -0,0 +1,32 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('short -k=v', function (t) {
+	t.plan(1);
+
+	var argv = parse(['-b=123']);
+	t.deepEqual(argv, { b: 123, _: [] });
+});
+
+test('multi short -k=v', function (t) {
+	t.plan(1);
+
+	var argv = parse(['-a=whatever', '-b=robots']);
+	t.deepEqual(argv, { a: 'whatever', b: 'robots', _: [] });
+});
+
+test('short with embedded equals -k=a=b', function (t) {
+	t.plan(1);
+
+	var argv = parse(['-k=a=b']);
+	t.deepEqual(argv, { k: 'a=b', _: [] });
+});
+
+test('short with later equals like -ab=c', function (t) {
+	t.plan(1);
+
+	var argv = parse(['-ab=c']);
+	t.deepEqual(argv, { a: true, b: 'c', _: [] });
+});

+ 33 - 0
node_modules/minimist/test/long.js

@@ -0,0 +1,33 @@
+'use strict';
+
+var test = require('tape');
+var parse = require('../');
+
+test('long opts', function (t) {
+	t.deepEqual(
+		parse(['--bool']),
+		{ bool: true, _: [] },
+		'long boolean'
+	);
+	t.deepEqual(
+		parse(['--pow', 'xixxle']),
+		{ pow: 'xixxle', _: [] },
+		'long capture sp'
+	);
+	t.deepEqual(
+		parse(['--pow=xixxle']),
+		{ pow: 'xixxle', _: [] },
+		'long capture eq'
+	);
+	t.deepEqual(
+		parse(['--host', 'localhost', '--port', '555']),
+		{ host: 'localhost', port: 555, _: [] },
+		'long captures sp'
+	);
+	t.deepEqual(
+		parse(['--host=localhost', '--port=555']),
+		{ host: 'localhost', port: 555, _: [] },
+		'long captures eq'
+	);
+	t.end();
+});

+ 38 - 0
node_modules/minimist/test/num.js

@@ -0,0 +1,38 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('nums', function (t) {
+	var argv = parse([
+		'-x', '1234',
+		'-y', '5.67',
+		'-z', '1e7',
+		'-w', '10f',
+		'--hex', '0xdeadbeef',
+		'789',
+	]);
+	t.deepEqual(argv, {
+		x: 1234,
+		y: 5.67,
+		z: 1e7,
+		w: '10f',
+		hex: 0xdeadbeef,
+		_: [789],
+	});
+	t.deepEqual(typeof argv.x, 'number');
+	t.deepEqual(typeof argv.y, 'number');
+	t.deepEqual(typeof argv.z, 'number');
+	t.deepEqual(typeof argv.w, 'string');
+	t.deepEqual(typeof argv.hex, 'number');
+	t.deepEqual(typeof argv._[0], 'number');
+	t.end();
+});
+
+test('already a number', function (t) {
+	var argv = parse(['-x', 1234, 789]);
+	t.deepEqual(argv, { x: 1234, _: [789] });
+	t.deepEqual(typeof argv.x, 'number');
+	t.deepEqual(typeof argv._[0], 'number');
+	t.end();
+});

+ 209 - 0
node_modules/minimist/test/parse.js

@@ -0,0 +1,209 @@
+'use strict';
+
+var parse = require('../');
+var test = require('tape');
+
+test('parse args', function (t) {
+	t.deepEqual(
+		parse(['--no-moo']),
+		{ moo: false, _: [] },
+		'no'
+	);
+	t.deepEqual(
+		parse(['-v', 'a', '-v', 'b', '-v', 'c']),
+		{ v: ['a', 'b', 'c'], _: [] },
+		'multi'
+	);
+	t.end();
+});
+
+test('comprehensive', function (t) {
+	t.deepEqual(
+		parse([
+			'--name=meowmers', 'bare', '-cats', 'woo',
+			'-h', 'awesome', '--multi=quux',
+			'--key', 'value',
+			'-b', '--bool', '--no-meep', '--multi=baz',
+			'--', '--not-a-flag', 'eek',
+		]),
+		{
+			c: true,
+			a: true,
+			t: true,
+			s: 'woo',
+			h: 'awesome',
+			b: true,
+			bool: true,
+			key: 'value',
+			multi: ['quux', 'baz'],
+			meep: false,
+			name: 'meowmers',
+			_: ['bare', '--not-a-flag', 'eek'],
+		}
+	);
+	t.end();
+});
+
+test('flag boolean', function (t) {
+	var argv = parse(['-t', 'moo'], { boolean: 't' });
+	t.deepEqual(argv, { t: true, _: ['moo'] });
+	t.deepEqual(typeof argv.t, 'boolean');
+	t.end();
+});
+
+test('flag boolean value', function (t) {
+	var argv = parse(['--verbose', 'false', 'moo', '-t', 'true'], {
+		boolean: ['t', 'verbose'],
+		default: { verbose: true },
+	});
+
+	t.deepEqual(argv, {
+		verbose: false,
+		t: true,
+		_: ['moo'],
+	});
+
+	t.deepEqual(typeof argv.verbose, 'boolean');
+	t.deepEqual(typeof argv.t, 'boolean');
+	t.end();
+});
+
+test('newlines in params', function (t) {
+	var args = parse(['-s', 'X\nX']);
+	t.deepEqual(args, { _: [], s: 'X\nX' });
+
+	// reproduce in bash:
+	// VALUE="new
+	// line"
+	// node program.js --s="$VALUE"
+	args = parse(['--s=X\nX']);
+	t.deepEqual(args, { _: [], s: 'X\nX' });
+	t.end();
+});
+
+test('strings', function (t) {
+	var s = parse(['-s', '0001234'], { string: 's' }).s;
+	t.equal(s, '0001234');
+	t.equal(typeof s, 'string');
+
+	var x = parse(['-x', '56'], { string: 'x' }).x;
+	t.equal(x, '56');
+	t.equal(typeof x, 'string');
+	t.end();
+});
+
+test('stringArgs', function (t) {
+	var s = parse(['  ', '  '], { string: '_' })._;
+	t.same(s.length, 2);
+	t.same(typeof s[0], 'string');
+	t.same(s[0], '  ');
+	t.same(typeof s[1], 'string');
+	t.same(s[1], '  ');
+	t.end();
+});
+
+test('empty strings', function (t) {
+	var s = parse(['-s'], { string: 's' }).s;
+	t.equal(s, '');
+	t.equal(typeof s, 'string');
+
+	var str = parse(['--str'], { string: 'str' }).str;
+	t.equal(str, '');
+	t.equal(typeof str, 'string');
+
+	var letters = parse(['-art'], {
+		string: ['a', 't'],
+	});
+
+	t.equal(letters.a, '');
+	t.equal(letters.r, true);
+	t.equal(letters.t, '');
+
+	t.end();
+});
+
+test('string and alias', function (t) {
+	var x = parse(['--str', '000123'], {
+		string: 's',
+		alias: { s: 'str' },
+	});
+
+	t.equal(x.str, '000123');
+	t.equal(typeof x.str, 'string');
+	t.equal(x.s, '000123');
+	t.equal(typeof x.s, 'string');
+
+	var y = parse(['-s', '000123'], {
+		string: 'str',
+		alias: { str: 's' },
+	});
+
+	t.equal(y.str, '000123');
+	t.equal(typeof y.str, 'string');
+	t.equal(y.s, '000123');
+	t.equal(typeof y.s, 'string');
+
+	var z = parse(['-s123'], {
+		alias: { str: ['s', 'S'] },
+		string: ['str'],
+	});
+
+	t.deepEqual(
+		z,
+		{ _: [], s: '123', S: '123', str: '123' },
+		'opt.string works with multiple aliases'
+	);
+	t.end();
+});
+
+test('slashBreak', function (t) {
+	t.same(
+		parse(['-I/foo/bar/baz']),
+		{ I: '/foo/bar/baz', _: [] }
+	);
+	t.same(
+		parse(['-xyz/foo/bar/baz']),
+		{ x: true, y: true, z: '/foo/bar/baz', _: [] }
+	);
+	t.end();
+});
+
+test('alias', function (t) {
+	var argv = parse(['-f', '11', '--zoom', '55'], {
+		alias: { z: 'zoom' },
+	});
+	t.equal(argv.zoom, 55);
+	t.equal(argv.z, argv.zoom);
+	t.equal(argv.f, 11);
+	t.end();
+});
+
+test('multiAlias', function (t) {
+	var argv = parse(['-f', '11', '--zoom', '55'], {
+		alias: { z: ['zm', 'zoom'] },
+	});
+	t.equal(argv.zoom, 55);
+	t.equal(argv.z, argv.zoom);
+	t.equal(argv.z, argv.zm);
+	t.equal(argv.f, 11);
+	t.end();
+});
+
+test('nested dotted objects', function (t) {
+	var argv = parse([
+		'--foo.bar', '3', '--foo.baz', '4',
+		'--foo.quux.quibble', '5', '--foo.quux.o_O',
+		'--beep.boop',
+	]);
+
+	t.same(argv.foo, {
+		bar: 3,
+		baz: 4,
+		quux: {
+			quibble: 5,
+			o_O: true,
+		},
+	});
+	t.same(argv.beep, { boop: true });
+	t.end();
+});

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません