Index: frontend/node_modules/webpack-dev-server/LICENSE
===================================================================
--- frontend/node_modules/webpack-dev-server/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+Copyright JS Foundation and other 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.
Index: frontend/node_modules/webpack-dev-server/README.md
===================================================================
--- frontend/node_modules/webpack-dev-server/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,345 @@
+<div align="center">
+  <a href="https://github.com/webpack/webpack">
+    <img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
+  </a>
+</div>
+
+[![npm][npm]][npm-url]
+[![node][node]][node-url]
+[![tests][tests]][tests-url]
+[![coverage][cover]][cover-url]
+[![chat][chat]][chat-url]
+[![downloads][downloads]][npm-url]
+[![contributors][contributors]][contributors-url]
+
+# webpack-dev-server
+
+Use [webpack](https://webpack.js.org) with a development server that provides
+live reloading. This should be used for **development only**.
+
+It uses [webpack-dev-middleware][middleware-url] under the hood, which provides
+fast in-memory access to the webpack assets.
+
+## Table of Contents
+
+- [Getting Started](#getting-started)
+- [Usage](#usage)
+  - [With the CLI](#with-the-cli)
+  - [With NPM Scripts](#with-npm-scripts)
+  - [With the API](#with-the-api)
+  - [With TypeScript](#with-typescript)
+  - [The Result](#the-result)
+- [Browser Support](#browser-support)
+- [Support](#support)
+- [Contributing](#contributing)
+- [Attribution](#attribution)
+- [License](#license)
+
+## Getting Started
+
+First things first, install the module:
+
+```console
+npm install webpack-dev-server --save-dev
+```
+
+or
+
+```console
+yarn add -D webpack-dev-server
+```
+
+or
+
+```console
+pnpm add -D webpack-dev-server
+```
+
+_Note: While you can install and run webpack-dev-server globally, we recommend
+installing it locally. webpack-dev-server will always use a local installation
+over a global one._
+
+## Usage
+
+There are two main, recommended methods of using the module:
+
+### With the CLI
+
+The easiest way to use it is with the [webpack CLI](https://webpack.js.org/api/cli/). In the directory where your
+`webpack.config.js` is, run:
+
+```console
+npx webpack serve
+```
+
+Following options are available with `webpack serve`:
+
+```
+Usage: webpack serve|server|s [entries...] [options]
+
+Run the webpack dev server.
+
+Options:
+  -c, --config <value...>                             Provide path to a webpack configuration file e.g. ./webpack.config.js.
+  --config-name <value...>                            Name of the configuration to use.
+  -m, --merge                                         Merge two or more configurations using 'webpack-merge'.
+  --env <value...>                                    Environment passed to the configuration when it is a function.
+  --node-env <value>                                  Sets process.env.NODE_ENV to the specified value.
+  --progress [value]                                  Print compilation progress during build.
+  -j, --json [value]                                  Prints result as JSON or store it in a file.
+  -d, --devtool <value>                               Determine source maps to use.
+  --no-devtool                                        Do not generate source maps.
+  --entry <value...>                                  The entry point(s) of your application e.g. ./src/main.js.
+  --mode <value>                                      Defines the mode to pass to webpack.
+  --name <value>                                      Name of the configuration. Used when loading multiple configurations.
+  -o, --output-path <value>                           Output location of the file generated by webpack e.g. ./dist/.
+  --stats [value]                                     It instructs webpack on how to treat the stats e.g. verbose.
+  --no-stats                                          Disable stats output.
+  -t, --target <value...>                             Sets the build target e.g. node.
+  --no-target                                         Negative 'target' option.
+  --watch-options-stdin                               Stop watching when stdin stream has ended.
+  --no-watch-options-stdin                            Do not stop watching when stdin stream has ended.
+  --allowed-hosts <value...>                          Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').
+  --allowed-hosts-reset                               Clear all items provided in 'allowedHosts' configuration. Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').
+  --bonjour                                           Allows to broadcasts dev server via ZeroConf networking on start.
+  --no-bonjour                                        Disallows to broadcasts dev server via ZeroConf networking on start.
+  --no-client                                         Disables client script.
+  --client-logging <value>                            Allows to set log level in the browser.
+  --client-overlay                                    Enables a full-screen overlay in the browser when there are compiler errors or warnings.
+  --no-client-overlay                                 Disables the full-screen overlay in the browser when there are compiler errors or warnings.
+  --client-overlay-errors                             Enables a full-screen overlay in the browser when there are compiler errors.
+  --no-client-overlay-errors                          Disables the full-screen overlay in the browser when there are compiler errors.
+  --client-overlay-warnings                           Enables a full-screen overlay in the browser when there are compiler warnings.
+  --no-client-overlay-warnings                        Disables the full-screen overlay in the browser when there are compiler warnings.
+  --client-overlay-trusted-types-policy-name <value>  The name of a Trusted Types policy for the overlay. Defaults to 'webpack-dev-server#overlay'.
+  --client-progress                                   Prints compilation progress in percentage in the browser.
+  --no-client-progress                                Does not print compilation progress in percentage in the browser.
+  --client-reconnect [value]                          Tells dev-server the number of times it should try to reconnect the client.
+  --no-client-reconnect                               Tells dev-server to not to try to reconnect the client.
+  --client-web-socket-transport <value>               Allows to set custom web socket transport to communicate with dev server.
+  --client-web-socket-url <value>                     Allows to specify URL to web socket server (useful when you're proxying dev server and client script does not always know where to connect to).
+  --client-web-socket-url-hostname <value>            Tells clients connected to devServer to use the provided hostname.
+  --client-web-socket-url-pathname <value>            Tells clients connected to devServer to use the provided path to connect.
+  --client-web-socket-url-password <value>            Tells clients connected to devServer to use the provided password to authenticate.
+  --client-web-socket-url-port <value>                Tells clients connected to devServer to use the provided port.
+  --client-web-socket-url-protocol <value>            Tells clients connected to devServer to use the provided protocol.
+  --client-web-socket-url-username <value>            Tells clients connected to devServer to use the provided username to authenticate.
+  --compress                                          Enables gzip compression for everything served.
+  --no-compress                                       Disables gzip compression for everything served.
+  --history-api-fallback                              Allows to proxy requests through a specified index page (by default 'index.html'), useful for Single Page Applications that utilise the HTML5 History API.
+  --no-history-api-fallback                           Disallows to proxy requests through a specified index page.
+  --host <value>                                      Allows to specify a hostname to use.
+  --hot [value]                                       Enables Hot Module Replacement.
+  --no-hot                                            Disables Hot Module Replacement.
+  --http2                                             Allows to serve over HTTP/2 using SPDY. Deprecated, use the `server` option.
+  --no-http2                                          Does not serve over HTTP/2 using SPDY.
+  --https                                             Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP). Deprecated, use the `server` option.
+  --no-https                                          Disallows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP).
+  --https-passphrase <value>                          Passphrase for a pfx file. Deprecated, use the `server.options.passphrase` option.
+  --https-request-cert                                Request for an SSL certificate. Deprecated, use the `server.options.requestCert` option.
+  --no-https-request-cert                             Does not request for an SSL certificate.
+  --https-ca <value...>                               Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.
+  --https-ca-reset                                    Clear all items provided in 'https.ca' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.
+  --https-cacert <value...>                           Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.
+  --https-cacert-reset                                Clear all items provided in 'https.cacert' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.
+  --https-cert <value...>                             Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option.
+  --https-cert-reset                                  Clear all items provided in 'https.cert' configuration. Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option.
+  --https-crl <value...>                              Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option.
+  --https-crl-reset                                   Clear all items provided in 'https.crl' configuration. Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option.
+  --https-key <value...>                              Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option.
+  --https-key-reset                                   Clear all items provided in 'https.key' configuration. Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option.
+  --https-pfx <value...>                              Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option.
+  --https-pfx-reset                                   Clear all items provided in 'https.pfx' configuration. Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option.
+  --ipc [value]                                       Listen to a unix socket.
+  --live-reload                                       Enables reload/refresh the page(s) when file changes are detected (enabled by default).
+  --no-live-reload                                    Disables reload/refresh the page(s) when file changes are detected (enabled by default).
+  --magic-html                                        Tells dev-server whether to enable magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js').
+  --no-magic-html                                     Disables magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js').
+  --open [value...]                                   Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).
+  --no-open                                           Does not open the default browser.
+  --open-target <value...>                            Opens specified page in browser.
+  --open-app-name <value...>                          Open specified browser.
+  --open-app <value...>                               Open specified browser. Deprecated: please use '--open-app-name'.
+  --open-reset                                        Clear all items provided in 'open' configuration. Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).
+  --open-target-reset                                 Clear all items provided in 'open.target' configuration. Opens specified page in browser.
+  --open-app-name-reset                               Clear all items provided in 'open.app.name' configuration. Open specified browser.
+  --port <value>                                      Allows to specify a port to use.
+  --server-type <value>                               Allows to set server and options (by default 'http').
+  --server-options-passphrase <value>                 Passphrase for a pfx file.
+  --server-options-request-cert                       Request for an SSL certificate.
+  --no-server-options-request-cert                    Does not request for an SSL certificate.
+  --server-options-ca <value...>                      Path to an SSL CA certificate or content of an SSL CA certificate.
+  --server-options-ca-reset                           Clear all items provided in 'server.options.ca' configuration. Path to an SSL CA certificate or content of an SSL CA certificate.
+  --server-options-cacert <value...>                  Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.
+  --server-options-cacert-reset                       Clear all items provided in 'server.options.cacert' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.
+  --server-options-cert <value...>                    Path to an SSL certificate or content of an SSL certificate.
+  --server-options-cert-reset                         Clear all items provided in 'server.options.cert' configuration. Path to an SSL certificate or content of an SSL certificate.
+  --server-options-crl <value...>                     Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists).
+  --server-options-crl-reset                          Clear all items provided in 'server.options.crl' configuration. Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists).
+  --server-options-key <value...>                     Path to an SSL key or content of an SSL key.
+  --server-options-key-reset                          Clear all items provided in 'server.options.key' configuration. Path to an SSL key or content of an SSL key.
+  --server-options-pfx <value...>                     Path to an SSL pfx file or content of an SSL pfx file.
+  --server-options-pfx-reset                          Clear all items provided in 'server.options.pfx' configuration. Path to an SSL pfx file or content of an SSL pfx file.
+  --static [value...]                                 Allows to configure options for serving static files from directory (by default 'public' directory).
+  --no-static                                         Disallows to configure options for serving static files from directory.
+  --static-directory <value...>                       Directory for static contents.
+  --static-public-path <value...>                     The static files will be available in the browser under this public path.
+  --static-serve-index                                Tells dev server to use serveIndex middleware when enabled.
+  --no-static-serve-index                             Does not tell dev server to use serveIndex middleware.
+  --static-watch                                      Watches for files in static content directory.
+  --no-static-watch                                   Does not watch for files in static content directory.
+  --static-reset                                      Clear all items provided in 'static' configuration. Allows to configure options for serving static files from directory (by default 'public' directory).
+  --static-public-path-reset                          Clear all items provided in 'static.publicPath' configuration. The static files will be available in the browser under this public path.
+  --watch-files <value...>                            Allows to configure list of globs/directories/files to watch for file changes.
+  --watch-files-reset                                 Clear all items provided in 'watchFiles' configuration. Allows to configure list of globs/directories/files to watch for file changes.
+  --web-socket-server <value>                         Deprecated: please use '--web-socket-server-type' option. Allows to set web socket server and options (by default 'ws').
+  --no-web-socket-server                              Disallows to set web socket server and options.
+  --web-socket-server-type <value>                    Allows to set web socket server and options (by default 'ws').
+
+Global options:
+  --color                                             Enable colors on console.
+  --no-color                                          Disable colors on console.
+  -v, --version                                       Output the version number of 'webpack', 'webpack-cli' and 'webpack-dev-server' and commands.
+  -h, --help [verbose]                                Display help for commands and options.
+
+To see list of all supported commands and options run 'webpack --help=verbose'.
+
+Webpack documentation: https://webpack.js.org/.
+CLI documentation: https://webpack.js.org/api/cli/.
+Made with ♥ by the webpack team.
+```
+
+> **Note**
+>
+> _Detailed documentation for above options is available on this [link](https://webpack.js.org/configuration/dev-server/)._
+
+### With NPM Scripts
+
+NPM package.json scripts are a convenient and useful means to run locally installed
+binaries without having to be concerned about their full paths. Simply define a
+script as such:
+
+```json
+{
+  "scripts": {
+    "serve": "webpack serve"
+  }
+}
+```
+
+And run the following in your terminal/console:
+
+```console
+npm run serve
+```
+
+NPM will automatically refer to the the binary in `node_modules` for you, and
+execute the file or command.
+
+### With the API
+
+While it's recommended to run webpack-dev-server via the CLI, you may also choose to start a server via the API.
+
+See the related [API documentation for `webpack-dev-server`](https://webpack.js.org/api/webpack-dev-server/).
+
+### With TypeScript
+
+If you use TypeScript in the webpack config, you'll need to properly type `devServer` property in order to avoid TS errors (e.g. `'devServer' does not exist in type 'Configuration'`). For that use either:
+
+```ts
+/// <reference path="node_modules/webpack-dev-server/types/lib/Server.d.ts"/>
+import type { Configuration } from "webpack";
+
+// Your logic
+```
+
+Or you can import the type from `webpack-dev-server`, i.e.
+
+```ts
+import type { Configuration as DevServerConfiguration } from "webpack-dev-server";
+import type { Configuration } from "webpack";
+
+const devServer: DevServerConfiguration = {};
+const config: Configuration = { devServer };
+
+// module.exports
+export default config;
+```
+
+### The Result
+
+Either method will start a server instance and begin listening for connections
+from `localhost` on port `8080`.
+
+webpack-dev-server is configured by default to support live-reload of files as
+you edit your assets while the server is running.
+
+See [**the documentation**][docs-url] for more use cases and options.
+
+## Browser Support
+
+While `webpack-dev-server` transpiles the client (browser) scripts to an ES5
+state, the project only officially supports the _last two versions of major
+browsers_. We simply don't have the resources to support every whacky
+browser out there.
+
+If you find a bug with an obscure / old browser, we would actively welcome a
+Pull Request to resolve the bug.
+
+## Support
+
+We do our best to keep issues in the repository focused on bugs, features, and
+needed modifications to the code for the module. Because of that, we ask users
+with general support, "how-to", or "why isn't this working" questions to try one
+of the other support channels that are available.
+
+Your first-stop-shop for support for webpack-dev-server should be the excellent
+[documentation][docs-url] for the module. If you see an opportunity for improvement
+of those docs, please head over to the [webpack.js.org repo][wjo-url] and open a
+pull request.
+
+From there, we encourage users to visit the [webpack Gitter chat][chat-url] and
+talk to the fine folks there. If your quest for answers comes up dry in chat,
+head over to [StackOverflow][stack-url] and do a quick search or open a new
+question. Remember; It's always much easier to answer questions that include your
+`webpack.config.js` and relevant files!
+
+If you're twitter-savvy you can tweet [#webpack][hash-url] with your question
+and someone should be able to reach out and lend a hand.
+
+If you have discovered a :bug:, have a feature suggestion, or would like to see
+a modification, please feel free to create an issue on Github. _Note: The issue
+template isn't optional, so please be sure not to remove it, and please fill it
+out completely._
+
+## Contributing
+
+We welcome your contributions! Please have a read of [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to get involved.
+
+## Attribution
+
+This project is heavily inspired by [peerigon/nof5](https://github.com/peerigon/nof5).
+
+## License
+
+#### [MIT](./LICENSE)
+
+[npm]: https://img.shields.io/npm/v/webpack-dev-server.svg
+[npm-url]: https://npmjs.com/package/webpack-dev-server
+[node]: https://img.shields.io/node/v/webpack-dev-server.svg
+[node-url]: https://nodejs.org
+[tests]: https://github.com/webpack/webpack-dev-server/workflows/webpack-dev-server/badge.svg
+[tests-url]: https://github.com/webpack/webpack-dev-server/actions?query=workflow%3Awebpack-dev-server
+[cover]: https://codecov.io/gh/webpack/webpack-dev-server/branch/master/graph/badge.svg
+[cover-url]: https://codecov.io/gh/webpack/webpack-dev-server
+[chat]: https://badges.gitter.im/webpack/webpack.svg
+[chat-url]: https://gitter.im/webpack/webpack
+[docs-url]: https://webpack.js.org/configuration/dev-server/#devserver
+[hash-url]: https://twitter.com/search?q=webpack
+[middleware-url]: https://github.com/webpack/webpack-dev-middleware
+[stack-url]: https://stackoverflow.com/questions/tagged/webpack-dev-server
+[uglify-url]: https://github.com/webpack-contrib/uglifyjs-webpack-plugin
+[wjo-url]: https://github.com/webpack/webpack.js.org
+[downloads]: https://img.shields.io/npm/dm/webpack-dev-server.svg
+[contributors-url]: https://github.com/webpack/webpack-dev-server/graphs/contributors
+[contributors]: https://img.shields.io/github/contributors/webpack/webpack-dev-server.svg
Index: frontend/node_modules/webpack-dev-server/bin/cli-flags.js
===================================================================
--- frontend/node_modules/webpack-dev-server/bin/cli-flags.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/bin/cli-flags.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1294 @@
+"use strict";
+
+module.exports = {
+  "allowed-hosts": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').",
+        path: "allowedHosts[]",
+      },
+      {
+        description:
+          "Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').",
+        multiple: false,
+        path: "allowedHosts",
+        type: "enum",
+        values: ["auto", "all"],
+      },
+    ],
+    description:
+      "Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').",
+    multiple: true,
+    simpleType: "string",
+  },
+  "allowed-hosts-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'allowedHosts' configuration. Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').",
+        path: "allowedHosts",
+      },
+    ],
+    description:
+      "Clear all items provided in 'allowedHosts' configuration. Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  bonjour: {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Allows to broadcasts dev server via ZeroConf networking on start.",
+        negatedDescription:
+          "Disallows to broadcasts dev server via ZeroConf networking on start.",
+        path: "bonjour",
+      },
+    ],
+    description:
+      "Allows to broadcasts dev server via ZeroConf networking on start.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  client: {
+    configs: [
+      {
+        description:
+          "Allows to specify options for client script in the browser or disable client script.",
+        negatedDescription: "Disables client script.",
+        multiple: false,
+        path: "client",
+        type: "enum",
+        values: [false],
+      },
+    ],
+    description:
+      "Allows to specify options for client script in the browser or disable client script.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "client-logging": {
+    configs: [
+      {
+        type: "enum",
+        values: ["none", "error", "warn", "info", "log", "verbose"],
+        multiple: false,
+        description: "Allows to set log level in the browser.",
+        path: "client.logging",
+      },
+    ],
+    description: "Allows to set log level in the browser.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-overlay": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Enables a full-screen overlay in the browser when there are compiler errors or warnings.",
+        negatedDescription:
+          "Disables the full-screen overlay in the browser when there are compiler errors or warnings.",
+        path: "client.overlay",
+      },
+    ],
+    description:
+      "Enables a full-screen overlay in the browser when there are compiler errors or warnings.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "client-overlay-errors": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Enables a full-screen overlay in the browser when there are compiler errors.",
+        negatedDescription:
+          "Disables the full-screen overlay in the browser when there are compiler errors.",
+        path: "client.overlay.errors",
+      },
+    ],
+    description:
+      "Enables a full-screen overlay in the browser when there are compiler errors.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "client-overlay-trusted-types-policy-name": {
+    configs: [
+      {
+        description:
+          "The name of a Trusted Types policy for the overlay. Defaults to 'webpack-dev-server#overlay'.",
+        multiple: false,
+        path: "client.overlay.trustedTypesPolicyName",
+        type: "string",
+      },
+    ],
+    description:
+      "The name of a Trusted Types policy for the overlay. Defaults to 'webpack-dev-server#overlay'.",
+    multiple: false,
+    simpleType: "string",
+  },
+  "client-overlay-warnings": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Enables a full-screen overlay in the browser when there are compiler warnings.",
+        negatedDescription:
+          "Disables the full-screen overlay in the browser when there are compiler warnings.",
+        path: "client.overlay.warnings",
+      },
+    ],
+    description:
+      "Enables a full-screen overlay in the browser when there are compiler warnings.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "client-overlay-runtime-errors": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Enables a full-screen overlay in the browser when there are uncaught runtime errors.",
+        negatedDescription:
+          "Disables the full-screen overlay in the browser when there are uncaught runtime errors.",
+        path: "client.overlay.runtimeErrors",
+      },
+    ],
+    description:
+      "Enables a full-screen overlay in the browser when there are uncaught runtime errors.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "client-progress": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Prints compilation progress in percentage in the browser.",
+        negatedDescription:
+          "Does not print compilation progress in percentage in the browser.",
+        path: "client.progress",
+      },
+    ],
+    description: "Prints compilation progress in percentage in the browser.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "client-reconnect": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Tells dev-server the number of times it should try to reconnect the client.",
+        negatedDescription:
+          "Tells dev-server to not to try to reconnect the client.",
+        path: "client.reconnect",
+      },
+      {
+        type: "number",
+        multiple: false,
+        description:
+          "Tells dev-server the number of times it should try to reconnect the client.",
+        path: "client.reconnect",
+      },
+    ],
+    description:
+      "Tells dev-server the number of times it should try to reconnect the client.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-transport": {
+    configs: [
+      {
+        type: "enum",
+        values: ["sockjs", "ws"],
+        multiple: false,
+        description:
+          "Allows to set custom web socket transport to communicate with dev server.",
+        path: "client.webSocketTransport",
+      },
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Allows to set custom web socket transport to communicate with dev server.",
+        path: "client.webSocketTransport",
+      },
+    ],
+    description:
+      "Allows to set custom web socket transport to communicate with dev server.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-url": {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Allows to specify URL to web socket server (useful when you're proxying dev server and client script does not always know where to connect to).",
+        path: "client.webSocketURL",
+      },
+    ],
+    description:
+      "Allows to specify URL to web socket server (useful when you're proxying dev server and client script does not always know where to connect to).",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-url-hostname": {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Tells clients connected to devServer to use the provided hostname.",
+        path: "client.webSocketURL.hostname",
+      },
+    ],
+    description:
+      "Tells clients connected to devServer to use the provided hostname.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-url-password": {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Tells clients connected to devServer to use the provided password to authenticate.",
+        path: "client.webSocketURL.password",
+      },
+    ],
+    description:
+      "Tells clients connected to devServer to use the provided password to authenticate.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-url-pathname": {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Tells clients connected to devServer to use the provided path to connect.",
+        path: "client.webSocketURL.pathname",
+      },
+    ],
+    description:
+      "Tells clients connected to devServer to use the provided path to connect.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-url-port": {
+    configs: [
+      {
+        type: "number",
+        multiple: false,
+        description:
+          "Tells clients connected to devServer to use the provided port.",
+        path: "client.webSocketURL.port",
+      },
+      {
+        description:
+          "Tells clients connected to devServer to use the provided port.",
+        multiple: false,
+        path: "client.webSocketURL.port",
+        type: "string",
+      },
+    ],
+    description:
+      "Tells clients connected to devServer to use the provided port.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "client-web-socket-url-protocol": {
+    configs: [
+      {
+        description:
+          "Tells clients connected to devServer to use the provided protocol.",
+        multiple: false,
+        path: "client.webSocketURL.protocol",
+        type: "enum",
+        values: ["auto"],
+      },
+      {
+        description:
+          "Tells clients connected to devServer to use the provided protocol.",
+        multiple: false,
+        path: "client.webSocketURL.protocol",
+        type: "string",
+      },
+    ],
+    description:
+      "Tells clients connected to devServer to use the provided protocol.",
+    multiple: false,
+    simpleType: "string",
+  },
+  "client-web-socket-url-username": {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Tells clients connected to devServer to use the provided username to authenticate.",
+        path: "client.webSocketURL.username",
+      },
+    ],
+    description:
+      "Tells clients connected to devServer to use the provided username to authenticate.",
+    simpleType: "string",
+    multiple: false,
+  },
+  compress: {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description: "Enables gzip compression for everything served.",
+        negatedDescription: "Disables gzip compression for everything served.",
+        path: "compress",
+      },
+    ],
+    description: "Enables gzip compression for everything served.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "history-api-fallback": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Allows to proxy requests through a specified index page (by default 'index.html'), useful for Single Page Applications that utilise the HTML5 History API.",
+        negatedDescription:
+          "Disallows to proxy requests through a specified index page.",
+        path: "historyApiFallback",
+      },
+    ],
+    description:
+      "Allows to proxy requests through a specified index page (by default 'index.html'), useful for Single Page Applications that utilise the HTML5 History API.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  host: {
+    configs: [
+      {
+        description: "Allows to specify a hostname to use.",
+        multiple: false,
+        path: "host",
+        type: "enum",
+        values: ["local-ip", "local-ipv4", "local-ipv6"],
+      },
+      {
+        description: "Allows to specify a hostname to use.",
+        multiple: false,
+        path: "host",
+        type: "string",
+      },
+    ],
+    description: "Allows to specify a hostname to use.",
+    simpleType: "string",
+    multiple: false,
+  },
+  hot: {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description: "Enables Hot Module Replacement.",
+        negatedDescription: "Disables Hot Module Replacement.",
+        path: "hot",
+      },
+      {
+        type: "enum",
+        values: ["only"],
+        multiple: false,
+        description: "Enables Hot Module Replacement.",
+        path: "hot",
+      },
+    ],
+    description: "Enables Hot Module Replacement.",
+    simpleType: "string",
+    multiple: false,
+  },
+  http2: {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Allows to serve over HTTP/2 using SPDY. Deprecated, use the `server` option.",
+        negatedDescription: "Does not serve over HTTP/2 using SPDY.",
+        path: "http2",
+      },
+    ],
+    description:
+      "Allows to serve over HTTP/2 using SPDY. Deprecated, use the `server` option.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  https: {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP). Deprecated, use the `server` option.",
+        negatedDescription:
+          "Disallows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP).",
+        path: "https",
+      },
+    ],
+    description:
+      "Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP). Deprecated, use the `server` option.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "https-ca": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+        path: "https.ca[]",
+      },
+    ],
+    description:
+      "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "https-ca-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'https.ca' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+        multiple: false,
+        path: "https.ca",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'https.ca' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "https-cacert": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+        path: "https.cacert[]",
+      },
+    ],
+    description:
+      "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "https-cacert-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'https.cacert' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+        multiple: false,
+        path: "https.cacert",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'https.cacert' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "https-cert": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option.",
+        path: "https.cert[]",
+      },
+    ],
+    description:
+      "Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "https-cert-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'https.cert' configuration. Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option.",
+        multiple: false,
+        path: "https.cert",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'https.cert' configuration. Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "https-crl": {
+    configs: [
+      {
+        description:
+          "Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option.",
+        multiple: true,
+        path: "https.crl[]",
+        type: "string",
+      },
+    ],
+    description:
+      "Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option.",
+    multiple: true,
+    simpleType: "string",
+  },
+  "https-crl-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'https.crl' configuration. Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option.",
+        multiple: false,
+        path: "https.crl",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'https.crl' configuration. Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "https-key": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option.",
+        path: "https.key[]",
+      },
+    ],
+    description:
+      "Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "https-key-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'https.key' configuration. Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option.",
+        multiple: false,
+        path: "https.key",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'https.key' configuration. Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "https-passphrase": {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description:
+          "Passphrase for a pfx file. Deprecated, use the `server.options.passphrase` option.",
+        path: "https.passphrase",
+      },
+    ],
+    description:
+      "Passphrase for a pfx file. Deprecated, use the `server.options.passphrase` option.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "https-pfx": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option.",
+        path: "https.pfx[]",
+      },
+    ],
+    description:
+      "Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "https-pfx-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'https.pfx' configuration. Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option.",
+        multiple: false,
+        path: "https.pfx",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'https.pfx' configuration. Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "https-request-cert": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Request for an SSL certificate. Deprecated, use the `server.options.requestCert` option.",
+        negatedDescription: "Does not request for an SSL certificate.",
+        path: "https.requestCert",
+      },
+    ],
+    description:
+      "Request for an SSL certificate. Deprecated, use the `server.options.requestCert` option.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  ipc: {
+    configs: [
+      {
+        type: "string",
+        multiple: false,
+        description: "Listen to a unix socket.",
+        path: "ipc",
+      },
+      {
+        type: "enum",
+        values: [true],
+        multiple: false,
+        description: "Listen to a unix socket.",
+        path: "ipc",
+      },
+    ],
+    description: "Listen to a unix socket.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "live-reload": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Enables reload/refresh the page(s) when file changes are detected (enabled by default).",
+        negatedDescription:
+          "Disables reload/refresh the page(s) when file changes are detected (enabled by default).",
+        path: "liveReload",
+      },
+    ],
+    description:
+      "Enables reload/refresh the page(s) when file changes are detected (enabled by default).",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "magic-html": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Tells dev-server whether to enable magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js').",
+        negatedDescription:
+          "Disables magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js').",
+        path: "magicHtml",
+      },
+    ],
+    description:
+      "Tells dev-server whether to enable magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js').",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  open: {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).",
+        path: "open[]",
+      },
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).",
+        negatedDescription: "Does not open the default browser.",
+        path: "open",
+      },
+    ],
+    description:
+      "Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).",
+    simpleType: "string",
+    multiple: true,
+  },
+  "open-app": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Open specified browser. Deprecated: please use '--open-app-name'.",
+        path: "open[].app",
+      },
+    ],
+    description:
+      "Open specified browser. Deprecated: please use '--open-app-name'.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "open-app-name": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description: "Open specified browser.",
+        path: "open[].app.name",
+      },
+      {
+        type: "string",
+        multiple: true,
+        description: "Open specified browser.",
+        path: "open.app.name[]",
+      },
+    ],
+    description: "Open specified browser.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "open-app-name-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'open.app.name' configuration. Open specified browser.",
+        path: "open.app.name",
+      },
+    ],
+    description:
+      "Clear all items provided in 'open.app.name' configuration. Open specified browser.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "open-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'open' configuration. Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).",
+        path: "open",
+      },
+    ],
+    description:
+      "Clear all items provided in 'open' configuration. Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "open-target": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description: "Opens specified page in browser.",
+        path: "open[].target",
+      },
+      {
+        type: "string",
+        multiple: true,
+        description: "Opens specified page in browser.",
+        path: "open.target[]",
+      },
+    ],
+    description: "Opens specified page in browser.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "open-target-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'open.target' configuration. Opens specified page in browser.",
+        path: "open.target",
+      },
+    ],
+    description:
+      "Clear all items provided in 'open.target' configuration. Opens specified page in browser.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  port: {
+    configs: [
+      {
+        type: "number",
+        multiple: false,
+        description: "Allows to specify a port to use.",
+        path: "port",
+      },
+      {
+        type: "string",
+        multiple: false,
+        description: "Allows to specify a port to use.",
+        path: "port",
+      },
+      {
+        type: "enum",
+        values: ["auto"],
+        multiple: false,
+        description: "Allows to specify a port to use.",
+        path: "port",
+      },
+    ],
+    description: "Allows to specify a port to use.",
+    simpleType: "string",
+    multiple: false,
+  },
+  "server-options-ca": {
+    configs: [
+      {
+        description:
+          "Path to an SSL CA certificate or content of an SSL CA certificate.",
+        multiple: true,
+        path: "server.options.ca[]",
+        type: "string",
+      },
+    ],
+    description:
+      "Path to an SSL CA certificate or content of an SSL CA certificate.",
+    multiple: true,
+    simpleType: "string",
+  },
+  "server-options-ca-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'server.options.ca' configuration. Path to an SSL CA certificate or content of an SSL CA certificate.",
+        multiple: false,
+        path: "server.options.ca",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'server.options.ca' configuration. Path to an SSL CA certificate or content of an SSL CA certificate.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-options-cacert": {
+    configs: [
+      {
+        description:
+          "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+        multiple: true,
+        path: "server.options.cacert[]",
+        type: "string",
+      },
+    ],
+    description:
+      "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+    multiple: true,
+    simpleType: "string",
+  },
+  "server-options-cacert-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'server.options.cacert' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+        multiple: false,
+        path: "server.options.cacert",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'server.options.cacert' configuration. Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-options-cert": {
+    configs: [
+      {
+        description:
+          "Path to an SSL certificate or content of an SSL certificate.",
+        multiple: true,
+        path: "server.options.cert[]",
+        type: "string",
+      },
+    ],
+    description: "Path to an SSL certificate or content of an SSL certificate.",
+    multiple: true,
+    simpleType: "string",
+  },
+  "server-options-cert-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'server.options.cert' configuration. Path to an SSL certificate or content of an SSL certificate.",
+        multiple: false,
+        path: "server.options.cert",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'server.options.cert' configuration. Path to an SSL certificate or content of an SSL certificate.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-options-crl": {
+    configs: [
+      {
+        description:
+          "Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists).",
+        multiple: true,
+        path: "server.options.crl[]",
+        type: "string",
+      },
+    ],
+    description:
+      "Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists).",
+    multiple: true,
+    simpleType: "string",
+  },
+  "server-options-crl-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'server.options.crl' configuration. Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists).",
+        multiple: false,
+        path: "server.options.crl",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'server.options.crl' configuration. Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists).",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-options-key": {
+    configs: [
+      {
+        description: "Path to an SSL key or content of an SSL key.",
+        multiple: true,
+        path: "server.options.key[]",
+        type: "string",
+      },
+    ],
+    description: "Path to an SSL key or content of an SSL key.",
+    multiple: true,
+    simpleType: "string",
+  },
+  "server-options-key-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'server.options.key' configuration. Path to an SSL key or content of an SSL key.",
+        multiple: false,
+        path: "server.options.key",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'server.options.key' configuration. Path to an SSL key or content of an SSL key.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-options-passphrase": {
+    configs: [
+      {
+        description: "Passphrase for a pfx file.",
+        multiple: false,
+        path: "server.options.passphrase",
+        type: "string",
+      },
+    ],
+    description: "Passphrase for a pfx file.",
+    multiple: false,
+    simpleType: "string",
+  },
+  "server-options-pfx": {
+    configs: [
+      {
+        description: "Path to an SSL pfx file or content of an SSL pfx file.",
+        multiple: true,
+        path: "server.options.pfx[]",
+        type: "string",
+      },
+    ],
+    description: "Path to an SSL pfx file or content of an SSL pfx file.",
+    multiple: true,
+    simpleType: "string",
+  },
+  "server-options-pfx-reset": {
+    configs: [
+      {
+        description:
+          "Clear all items provided in 'server.options.pfx' configuration. Path to an SSL pfx file or content of an SSL pfx file.",
+        multiple: false,
+        path: "server.options.pfx",
+        type: "reset",
+      },
+    ],
+    description:
+      "Clear all items provided in 'server.options.pfx' configuration. Path to an SSL pfx file or content of an SSL pfx file.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-options-request-cert": {
+    configs: [
+      {
+        description: "Request for an SSL certificate.",
+        negatedDescription: "Does not request for an SSL certificate.",
+        multiple: false,
+        path: "server.options.requestCert",
+        type: "boolean",
+      },
+    ],
+    description: "Request for an SSL certificate.",
+    multiple: false,
+    simpleType: "boolean",
+  },
+  "server-type": {
+    configs: [
+      {
+        description: "Allows to set server and options (by default 'http').",
+        multiple: false,
+        path: "server.type",
+        type: "enum",
+        values: ["http", "https", "spdy"],
+      },
+    ],
+    description: "Allows to set server and options (by default 'http').",
+    multiple: false,
+    simpleType: "string",
+  },
+  static: {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Allows to configure options for serving static files from directory (by default 'public' directory).",
+        path: "static[]",
+      },
+      {
+        type: "boolean",
+        multiple: false,
+        description:
+          "Allows to configure options for serving static files from directory (by default 'public' directory).",
+        negatedDescription:
+          "Disallows to configure options for serving static files from directory.",
+        path: "static",
+      },
+    ],
+    description:
+      "Allows to configure options for serving static files from directory (by default 'public' directory).",
+    simpleType: "string",
+    multiple: true,
+  },
+  "static-directory": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description: "Directory for static contents.",
+        path: "static[].directory",
+      },
+    ],
+    description: "Directory for static contents.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "static-public-path": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "The static files will be available in the browser under this public path.",
+        path: "static[].publicPath",
+      },
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "The static files will be available in the browser under this public path.",
+        path: "static.publicPath[]",
+      },
+    ],
+    description:
+      "The static files will be available in the browser under this public path.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "static-public-path-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'static.publicPath' configuration. The static files will be available in the browser under this public path.",
+        path: "static.publicPath",
+      },
+    ],
+    description:
+      "Clear all items provided in 'static.publicPath' configuration. The static files will be available in the browser under this public path.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "static-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'static' configuration. Allows to configure options for serving static files from directory (by default 'public' directory).",
+        path: "static",
+      },
+    ],
+    description:
+      "Clear all items provided in 'static' configuration. Allows to configure options for serving static files from directory (by default 'public' directory).",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "static-serve-index": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: true,
+        description:
+          "Tells dev server to use serveIndex middleware when enabled.",
+        negatedDescription:
+          "Does not tell dev server to use serveIndex middleware.",
+        path: "static[].serveIndex",
+      },
+    ],
+    description: "Tells dev server to use serveIndex middleware when enabled.",
+    simpleType: "boolean",
+    multiple: true,
+  },
+  "static-watch": {
+    configs: [
+      {
+        type: "boolean",
+        multiple: true,
+        description: "Watches for files in static content directory.",
+        negatedDescription:
+          "Does not watch for files in static content directory.",
+        path: "static[].watch",
+      },
+    ],
+    description: "Watches for files in static content directory.",
+    simpleType: "boolean",
+    multiple: true,
+  },
+  "watch-files": {
+    configs: [
+      {
+        type: "string",
+        multiple: true,
+        description:
+          "Allows to configure list of globs/directories/files to watch for file changes.",
+        path: "watchFiles[]",
+      },
+    ],
+    description:
+      "Allows to configure list of globs/directories/files to watch for file changes.",
+    simpleType: "string",
+    multiple: true,
+  },
+  "watch-files-reset": {
+    configs: [
+      {
+        type: "reset",
+        multiple: false,
+        description:
+          "Clear all items provided in 'watchFiles' configuration. Allows to configure list of globs/directories/files to watch for file changes.",
+        path: "watchFiles",
+      },
+    ],
+    description:
+      "Clear all items provided in 'watchFiles' configuration. Allows to configure list of globs/directories/files to watch for file changes.",
+    simpleType: "boolean",
+    multiple: false,
+  },
+  "web-socket-server": {
+    configs: [
+      {
+        description:
+          "Deprecated: please use '--web-socket-server-type' option.",
+        negatedDescription: "Disallows to set web socket server and options.",
+        multiple: false,
+        path: "webSocketServer",
+        type: "enum",
+        values: [false],
+      },
+      {
+        description:
+          "Deprecated: please use '--web-socket-server-type' option.",
+        multiple: false,
+        path: "webSocketServer",
+        type: "enum",
+        values: ["sockjs", "ws"],
+      },
+      {
+        description:
+          "Allows to set web socket server and options (by default 'ws').",
+        multiple: false,
+        path: "webSocketServer",
+        type: "string",
+      },
+    ],
+    description:
+      "Deprecated: please use '--web-socket-server-type' option. Allows to set web socket server and options (by default 'ws').",
+    simpleType: "string",
+    multiple: false,
+  },
+  "web-socket-server-type": {
+    configs: [
+      {
+        description:
+          "Allows to set web socket server and options (by default 'ws').",
+        multiple: false,
+        path: "webSocketServer.type",
+        type: "enum",
+        values: ["sockjs", "ws"],
+      },
+      {
+        description:
+          "Allows to set web socket server and options (by default 'ws').",
+        multiple: false,
+        path: "webSocketServer.type",
+        type: "string",
+      },
+    ],
+    description:
+      "Allows to set web socket server and options (by default 'ws').",
+    simpleType: "string",
+    multiple: false,
+  },
+};
Index: frontend/node_modules/webpack-dev-server/bin/process-arguments.js
===================================================================
--- frontend/node_modules/webpack-dev-server/bin/process-arguments.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/bin/process-arguments.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,412 @@
+"use strict";
+
+const path = require("path");
+
+// Based on https://github.com/webpack/webpack/blob/master/lib/cli.js
+// Please do not modify it
+
+/** @typedef {"unknown-argument" | "unexpected-non-array-in-path" | "unexpected-non-object-in-path" | "multiple-values-unexpected" | "invalid-value"} ProblemType */
+
+/**
+ * @typedef {Object} Problem
+ * @property {ProblemType} type
+ * @property {string} path
+ * @property {string} argument
+ * @property {any=} value
+ * @property {number=} index
+ * @property {string=} expected
+ */
+
+/**
+ * @typedef {Object} LocalProblem
+ * @property {ProblemType} type
+ * @property {string} path
+ * @property {string=} expected
+ */
+
+/**
+ * @typedef {Object} ArgumentConfig
+ * @property {string} description
+ * @property {string} path
+ * @property {boolean} multiple
+ * @property {"enum"|"string"|"path"|"number"|"boolean"|"RegExp"|"reset"} type
+ * @property {any[]=} values
+ */
+
+/**
+ * @typedef {Object} Argument
+ * @property {string} description
+ * @property {"string"|"number"|"boolean"} simpleType
+ * @property {boolean} multiple
+ * @property {ArgumentConfig[]} configs
+ */
+
+const cliAddedItems = new WeakMap();
+
+/**
+ * @param {any} config configuration
+ * @param {string} schemaPath path in the config
+ * @param {number | undefined} index index of value when multiple values are provided, otherwise undefined
+ * @returns {{ problem?: LocalProblem, object?: any, property?: string | number, value?: any }} problem or object with property and value
+ */
+const getObjectAndProperty = (config, schemaPath, index = 0) => {
+  if (!schemaPath) {
+    return { value: config };
+  }
+
+  const parts = schemaPath.split(".");
+  const property = parts.pop();
+  let current = config;
+  let i = 0;
+
+  for (const part of parts) {
+    const isArray = part.endsWith("[]");
+    const name = isArray ? part.slice(0, -2) : part;
+    let value = current[name];
+
+    if (isArray) {
+      // eslint-disable-next-line no-undefined
+      if (value === undefined) {
+        value = {};
+        current[name] = [...Array.from({ length: index }), value];
+        cliAddedItems.set(current[name], index + 1);
+      } else if (!Array.isArray(value)) {
+        return {
+          problem: {
+            type: "unexpected-non-array-in-path",
+            path: parts.slice(0, i).join("."),
+          },
+        };
+      } else {
+        let addedItems = cliAddedItems.get(value) || 0;
+
+        while (addedItems <= index) {
+          // eslint-disable-next-line no-undefined
+          value.push(undefined);
+          // eslint-disable-next-line no-plusplus
+          addedItems++;
+        }
+
+        cliAddedItems.set(value, addedItems);
+
+        const x = value.length - addedItems + index;
+
+        // eslint-disable-next-line no-undefined
+        if (value[x] === undefined) {
+          value[x] = {};
+        } else if (value[x] === null || typeof value[x] !== "object") {
+          return {
+            problem: {
+              type: "unexpected-non-object-in-path",
+              path: parts.slice(0, i).join("."),
+            },
+          };
+        }
+
+        value = value[x];
+      }
+      // eslint-disable-next-line no-undefined
+    } else if (value === undefined) {
+      // eslint-disable-next-line no-multi-assign
+      value = current[name] = {};
+    } else if (value === null || typeof value !== "object") {
+      return {
+        problem: {
+          type: "unexpected-non-object-in-path",
+          path: parts.slice(0, i).join("."),
+        },
+      };
+    }
+
+    current = value;
+    // eslint-disable-next-line no-plusplus
+    i++;
+  }
+
+  const value = current[/** @type {string} */ (property)];
+
+  if (/** @type {string} */ (property).endsWith("[]")) {
+    const name = /** @type {string} */ (property).slice(0, -2);
+    // eslint-disable-next-line no-shadow
+    const value = current[name];
+
+    // eslint-disable-next-line no-undefined
+    if (value === undefined) {
+      // eslint-disable-next-line no-undefined
+      current[name] = [...Array.from({ length: index }), undefined];
+      cliAddedItems.set(current[name], index + 1);
+
+      // eslint-disable-next-line no-undefined
+      return { object: current[name], property: index, value: undefined };
+    } else if (!Array.isArray(value)) {
+      // eslint-disable-next-line no-undefined
+      current[name] = [value, ...Array.from({ length: index }), undefined];
+      cliAddedItems.set(current[name], index + 1);
+
+      // eslint-disable-next-line no-undefined
+      return { object: current[name], property: index + 1, value: undefined };
+    }
+
+    let addedItems = cliAddedItems.get(value) || 0;
+
+    while (addedItems <= index) {
+      // eslint-disable-next-line no-undefined
+      value.push(undefined);
+      // eslint-disable-next-line no-plusplus
+      addedItems++;
+    }
+
+    cliAddedItems.set(value, addedItems);
+
+    const x = value.length - addedItems + index;
+
+    // eslint-disable-next-line no-undefined
+    if (value[x] === undefined) {
+      value[x] = {};
+    } else if (value[x] === null || typeof value[x] !== "object") {
+      return {
+        problem: {
+          type: "unexpected-non-object-in-path",
+          path: schemaPath,
+        },
+      };
+    }
+
+    return {
+      object: value,
+      property: x,
+      value: value[x],
+    };
+  }
+
+  return { object: current, property, value };
+};
+
+/**
+ * @param {ArgumentConfig} argConfig processing instructions
+ * @param {any} value the value
+ * @returns {any | undefined} parsed value
+ */
+const parseValueForArgumentConfig = (argConfig, value) => {
+  // eslint-disable-next-line default-case
+  switch (argConfig.type) {
+    case "string":
+      if (typeof value === "string") {
+        return value;
+      }
+      break;
+    case "path":
+      if (typeof value === "string") {
+        return path.resolve(value);
+      }
+      break;
+    case "number":
+      if (typeof value === "number") {
+        return value;
+      }
+
+      if (typeof value === "string" && /^[+-]?\d*(\.\d*)[eE]\d+$/) {
+        const n = +value;
+        if (!isNaN(n)) return n;
+      }
+
+      break;
+    case "boolean":
+      if (typeof value === "boolean") {
+        return value;
+      }
+
+      if (value === "true") {
+        return true;
+      }
+
+      if (value === "false") {
+        return false;
+      }
+
+      break;
+    case "RegExp":
+      if (value instanceof RegExp) {
+        return value;
+      }
+
+      if (typeof value === "string") {
+        // cspell:word yugi
+        const match = /^\/(.*)\/([yugi]*)$/.exec(value);
+
+        if (match && !/[^\\]\//.test(match[1])) {
+          return new RegExp(match[1], match[2]);
+        }
+      }
+
+      break;
+    case "enum":
+      if (/** @type {any[]} */ (argConfig.values).includes(value)) {
+        return value;
+      }
+
+      for (const item of /** @type {any[]} */ (argConfig.values)) {
+        if (`${item}` === value) return item;
+      }
+
+      break;
+    case "reset":
+      if (value === true) {
+        return [];
+      }
+
+      break;
+  }
+};
+
+/**
+ * @param {ArgumentConfig} argConfig processing instructions
+ * @returns {string | undefined} expected message
+ */
+const getExpectedValue = (argConfig) => {
+  switch (argConfig.type) {
+    default:
+      return argConfig.type;
+    case "boolean":
+      return "true | false";
+    case "RegExp":
+      return "regular expression (example: /ab?c*/)";
+    case "enum":
+      return /** @type {any[]} */ (argConfig.values)
+        .map((v) => `${v}`)
+        .join(" | ");
+    case "reset":
+      return "true (will reset the previous value to an empty array)";
+  }
+};
+
+/**
+ * @param {any} config configuration
+ * @param {string} schemaPath path in the config
+ * @param {any} value parsed value
+ * @param {number | undefined} index index of value when multiple values are provided, otherwise undefined
+ * @returns {LocalProblem | null} problem or null for success
+ */
+const setValue = (config, schemaPath, value, index) => {
+  const { problem, object, property } = getObjectAndProperty(
+    config,
+    schemaPath,
+    index
+  );
+
+  if (problem) {
+    return problem;
+  }
+
+  object[/** @type {string} */ (property)] = value;
+
+  return null;
+};
+
+/**
+ * @param {ArgumentConfig} argConfig processing instructions
+ * @param {any} config configuration
+ * @param {any} value the value
+ * @param {number | undefined} index the index if multiple values provided
+ * @returns {LocalProblem | null} a problem if any
+ */
+const processArgumentConfig = (argConfig, config, value, index) => {
+  // eslint-disable-next-line no-undefined
+  if (index !== undefined && !argConfig.multiple) {
+    return {
+      type: "multiple-values-unexpected",
+      path: argConfig.path,
+    };
+  }
+
+  const parsed = parseValueForArgumentConfig(argConfig, value);
+
+  // eslint-disable-next-line no-undefined
+  if (parsed === undefined) {
+    return {
+      type: "invalid-value",
+      path: argConfig.path,
+      expected: getExpectedValue(argConfig),
+    };
+  }
+
+  const problem = setValue(config, argConfig.path, parsed, index);
+
+  if (problem) {
+    return problem;
+  }
+
+  return null;
+};
+
+/**
+ * @param {Record<string, Argument>} args object of arguments
+ * @param {any} config configuration
+ * @param {Record<string, string | number | boolean | RegExp | (string | number | boolean | RegExp)[]>} values object with values
+ * @returns {Problem[] | null} problems or null for success
+ */
+const processArguments = (args, config, values) => {
+  /**
+   * @type {Problem[]}
+   */
+  const problems = [];
+
+  for (const key of Object.keys(values)) {
+    const arg = args[key];
+
+    if (!arg) {
+      problems.push({
+        type: "unknown-argument",
+        path: "",
+        argument: key,
+      });
+
+      // eslint-disable-next-line no-continue
+      continue;
+    }
+
+    /**
+     * @param {any} value
+     * @param {number | undefined} i
+     */
+    const processValue = (value, i) => {
+      const currentProblems = [];
+
+      for (const argConfig of arg.configs) {
+        const problem = processArgumentConfig(argConfig, config, value, i);
+
+        if (!problem) {
+          return;
+        }
+
+        currentProblems.push({
+          ...problem,
+          argument: key,
+          value,
+          index: i,
+        });
+      }
+
+      problems.push(...currentProblems);
+    };
+
+    const value = values[key];
+
+    if (Array.isArray(value)) {
+      for (let i = 0; i < value.length; i++) {
+        processValue(value[i], i);
+      }
+    } else {
+      // eslint-disable-next-line no-undefined
+      processValue(value, undefined);
+    }
+  }
+
+  if (problems.length === 0) {
+    return null;
+  }
+
+  return problems;
+};
+
+module.exports = processArguments;
Index: frontend/node_modules/webpack-dev-server/bin/webpack-dev-server.js
===================================================================
--- frontend/node_modules/webpack-dev-server/bin/webpack-dev-server.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/bin/webpack-dev-server.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,199 @@
+#!/usr/bin/env node
+/* Based on webpack/bin/webpack.js */
+/* eslint-disable no-console */
+
+"use strict";
+
+/**
+ * @param {string} command process to run
+ * @param {string[]} args command line arguments
+ * @returns {Promise<void>} promise
+ */
+const runCommand = (command, args) => {
+  const cp = require("child_process");
+  return new Promise((resolve, reject) => {
+    const executedCommand = cp.spawn(command, args, {
+      stdio: "inherit",
+      shell: true,
+    });
+
+    executedCommand.on("error", (error) => {
+      reject(error);
+    });
+
+    executedCommand.on("exit", (code) => {
+      if (code === 0) {
+        resolve();
+      } else {
+        reject();
+      }
+    });
+  });
+};
+
+/**
+ * @param {string} packageName name of the package
+ * @returns {boolean} is the package installed?
+ */
+const isInstalled = (packageName) => {
+  if (process.versions.pnp) {
+    return true;
+  }
+
+  const path = require("path");
+  const fs = require("graceful-fs");
+
+  let dir = __dirname;
+
+  do {
+    try {
+      if (
+        fs.statSync(path.join(dir, "node_modules", packageName)).isDirectory()
+      ) {
+        return true;
+      }
+    } catch (_error) {
+      // Nothing
+    }
+    // eslint-disable-next-line no-cond-assign
+  } while (dir !== (dir = path.dirname(dir)));
+
+  // https://github.com/nodejs/node/blob/v18.9.1/lib/internal/modules/cjs/loader.js#L1274
+  // @ts-ignore
+  for (const internalPath of require("module").globalPaths) {
+    try {
+      if (fs.statSync(path.join(internalPath, packageName)).isDirectory()) {
+        return true;
+      }
+    } catch (_error) {
+      // Nothing
+    }
+  }
+
+  return false;
+};
+
+/**
+ * @param {CliOption} cli options
+ * @returns {void}
+ */
+const runCli = (cli) => {
+  if (cli.preprocess) {
+    cli.preprocess();
+  }
+  const path = require("path");
+  const pkgPath = require.resolve(`${cli.package}/package.json`);
+  // eslint-disable-next-line import/no-dynamic-require
+  const pkg = require(pkgPath);
+
+  if (pkg.type === "module" || /\.mjs/i.test(pkg.bin[cli.binName])) {
+    import(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName])).catch(
+      (error) => {
+        console.error(error);
+        process.exitCode = 1;
+      }
+    );
+  } else {
+    // eslint-disable-next-line import/no-dynamic-require
+    require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]));
+  }
+};
+
+/**
+ * @typedef {Object} CliOption
+ * @property {string} name display name
+ * @property {string} package npm package name
+ * @property {string} binName name of the executable file
+ * @property {boolean} installed currently installed?
+ * @property {string} url homepage
+ * @property {function} preprocess preprocessor
+ */
+
+/** @type {CliOption} */
+const cli = {
+  name: "webpack-cli",
+  package: "webpack-cli",
+  binName: "webpack-cli",
+  installed: isInstalled("webpack-cli"),
+  url: "https://github.com/webpack/webpack-cli",
+  preprocess() {
+    process.argv.splice(2, 0, "serve");
+  },
+};
+
+if (!cli.installed) {
+  const path = require("path");
+  const fs = require("graceful-fs");
+  const readLine = require("readline");
+
+  const notify = `CLI for webpack must be installed.\n  ${cli.name} (${cli.url})\n`;
+
+  console.error(notify);
+
+  /**
+   * @type {string}
+   */
+  let packageManager;
+
+  if (fs.existsSync(path.resolve(process.cwd(), "yarn.lock"))) {
+    packageManager = "yarn";
+  } else if (fs.existsSync(path.resolve(process.cwd(), "pnpm-lock.yaml"))) {
+    packageManager = "pnpm";
+  } else {
+    packageManager = "npm";
+  }
+
+  const installOptions = [packageManager === "yarn" ? "add" : "install", "-D"];
+
+  console.error(
+    `We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
+      " "
+    )} ${cli.package}".`
+  );
+
+  const question = `Do you want to install 'webpack-cli' (yes/no): `;
+
+  const questionInterface = readLine.createInterface({
+    input: process.stdin,
+    output: process.stderr,
+  });
+
+  // In certain scenarios (e.g. when STDIN is not in terminal mode), the callback function will not be
+  // executed. Setting the exit code here to ensure the script exits correctly in those cases. The callback
+  // function is responsible for clearing the exit code if the user wishes to install webpack-cli.
+  process.exitCode = 1;
+  questionInterface.question(question, (answer) => {
+    questionInterface.close();
+
+    const normalizedAnswer = answer.toLowerCase().startsWith("y");
+
+    if (!normalizedAnswer) {
+      console.error(
+        "You need to install 'webpack-cli' to use webpack via CLI.\n" +
+          "You can also install the CLI manually."
+      );
+
+      return;
+    }
+    process.exitCode = 0;
+
+    console.log(
+      `Installing '${
+        cli.package
+      }' (running '${packageManager} ${installOptions.join(" ")} ${
+        cli.package
+      }')...`
+    );
+
+    runCommand(packageManager, installOptions.concat(cli.package))
+      .then(() => {
+        runCli(cli);
+      })
+      .catch((error) => {
+        console.error(error);
+        process.exitCode = 1;
+      });
+  });
+} else {
+  runCli(cli);
+}
Index: frontend/node_modules/webpack-dev-server/client/clients/SockJSClient.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/clients/SockJSClient.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/clients/SockJSClient.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,61 @@
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
+function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
+function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
+import SockJS from "../modules/sockjs-client/index.js";
+import { log } from "../utils/log.js";
+var SockJSClient = /*#__PURE__*/function () {
+  /**
+   * @param {string} url
+   */
+  function SockJSClient(url) {
+    _classCallCheck(this, SockJSClient);
+    // SockJS requires `http` and `https` protocols
+    this.sock = new SockJS(url.replace(/^ws:/i, "http:").replace(/^wss:/i, "https:"));
+    this.sock.onerror =
+    /**
+     * @param {Error} error
+     */
+    function (error) {
+      log.error(error);
+    };
+  }
+
+  /**
+   * @param {(...args: any[]) => void} f
+   */
+  _createClass(SockJSClient, [{
+    key: "onOpen",
+    value: function onOpen(f) {
+      this.sock.onopen = f;
+    }
+
+    /**
+     * @param {(...args: any[]) => void} f
+     */
+  }, {
+    key: "onClose",
+    value: function onClose(f) {
+      this.sock.onclose = f;
+    }
+
+    // call f with the message string as the first argument
+    /**
+     * @param {(...args: any[]) => void} f
+     */
+  }, {
+    key: "onMessage",
+    value: function onMessage(f) {
+      this.sock.onmessage =
+      /**
+       * @param {Error & { data: string }} e
+       */
+      function (e) {
+        f(e.data);
+      };
+    }
+  }]);
+  return SockJSClient;
+}();
+export { SockJSClient as default };
Index: frontend/node_modules/webpack-dev-server/client/clients/WebSocketClient.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/clients/WebSocketClient.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/clients/WebSocketClient.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
+function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
+function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
+function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
+import { log } from "../utils/log.js";
+var WebSocketClient = /*#__PURE__*/function () {
+  /**
+   * @param {string} url
+   */
+  function WebSocketClient(url) {
+    _classCallCheck(this, WebSocketClient);
+    this.client = new WebSocket(url);
+    this.client.onerror = function (error) {
+      log.error(error);
+    };
+  }
+
+  /**
+   * @param {(...args: any[]) => void} f
+   */
+  _createClass(WebSocketClient, [{
+    key: "onOpen",
+    value: function onOpen(f) {
+      this.client.onopen = f;
+    }
+
+    /**
+     * @param {(...args: any[]) => void} f
+     */
+  }, {
+    key: "onClose",
+    value: function onClose(f) {
+      this.client.onclose = f;
+    }
+
+    // call f with the message string as the first argument
+    /**
+     * @param {(...args: any[]) => void} f
+     */
+  }, {
+    key: "onMessage",
+    value: function onMessage(f) {
+      this.client.onmessage = function (e) {
+        f(e.data);
+      };
+    }
+  }]);
+  return WebSocketClient;
+}();
+export { WebSocketClient as default };
Index: frontend/node_modules/webpack-dev-server/client/index.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,320 @@
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
+function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
+/* global __resourceQuery, __webpack_hash__ */
+/// <reference types="webpack/module" />
+import webpackHotLog from "webpack/hot/log.js";
+import stripAnsi from "./utils/stripAnsi.js";
+import parseURL from "./utils/parseURL.js";
+import socket from "./socket.js";
+import { formatProblem, createOverlay } from "./overlay.js";
+import { log, logEnabledFeatures, setLogLevel } from "./utils/log.js";
+import sendMessage from "./utils/sendMessage.js";
+import reloadApp from "./utils/reloadApp.js";
+import createSocketURL from "./utils/createSocketURL.js";
+
+/**
+ * @typedef {Object} OverlayOptions
+ * @property {boolean | (error: Error) => boolean} [warnings]
+ * @property {boolean | (error: Error) => boolean} [errors]
+ * @property {boolean | (error: Error) => boolean} [runtimeErrors]
+ * @property {string} [trustedTypesPolicyName]
+ */
+
+/**
+ * @typedef {Object} Options
+ * @property {boolean} hot
+ * @property {boolean} liveReload
+ * @property {boolean} progress
+ * @property {boolean | OverlayOptions} overlay
+ * @property {string} [logging]
+ * @property {number} [reconnect]
+ */
+
+/**
+ * @typedef {Object} Status
+ * @property {boolean} isUnloading
+ * @property {string} currentHash
+ * @property {string} [previousHash]
+ */
+
+/**
+ * @param {boolean | { warnings?: boolean | string; errors?: boolean | string; runtimeErrors?: boolean | string; }} overlayOptions
+ */
+var decodeOverlayOptions = function decodeOverlayOptions(overlayOptions) {
+  if (typeof overlayOptions === "object") {
+    ["warnings", "errors", "runtimeErrors"].forEach(function (property) {
+      if (typeof overlayOptions[property] === "string") {
+        var overlayFilterFunctionString = decodeURIComponent(overlayOptions[property]);
+
+        // eslint-disable-next-line no-new-func
+        var overlayFilterFunction = new Function("message", "var callback = ".concat(overlayFilterFunctionString, "\n        return callback(message)"));
+        overlayOptions[property] = overlayFilterFunction;
+      }
+    });
+  }
+};
+
+/**
+ * @type {Status}
+ */
+var status = {
+  isUnloading: false,
+  // TODO Workaround for webpack v4, `__webpack_hash__` is not replaced without HotModuleReplacement
+  // eslint-disable-next-line camelcase
+  currentHash: typeof __webpack_hash__ !== "undefined" ? __webpack_hash__ : ""
+};
+
+/** @type {Options} */
+var options = {
+  hot: false,
+  liveReload: false,
+  progress: false,
+  overlay: false
+};
+var parsedResourceQuery = parseURL(__resourceQuery);
+var enabledFeatures = {
+  "Hot Module Replacement": false,
+  "Live Reloading": false,
+  Progress: false,
+  Overlay: false
+};
+if (parsedResourceQuery.hot === "true") {
+  options.hot = true;
+  enabledFeatures["Hot Module Replacement"] = true;
+}
+if (parsedResourceQuery["live-reload"] === "true") {
+  options.liveReload = true;
+  enabledFeatures["Live Reloading"] = true;
+}
+if (parsedResourceQuery.progress === "true") {
+  options.progress = true;
+  enabledFeatures.Progress = true;
+}
+if (parsedResourceQuery.overlay) {
+  try {
+    options.overlay = JSON.parse(parsedResourceQuery.overlay);
+  } catch (e) {
+    log.error("Error parsing overlay options from resource query:", e);
+  }
+
+  // Fill in default "true" params for partially-specified objects.
+  if (typeof options.overlay === "object") {
+    options.overlay = _objectSpread({
+      errors: true,
+      warnings: true,
+      runtimeErrors: true
+    }, options.overlay);
+    decodeOverlayOptions(options.overlay);
+  }
+  enabledFeatures.Overlay = true;
+}
+if (parsedResourceQuery.logging) {
+  options.logging = parsedResourceQuery.logging;
+}
+if (typeof parsedResourceQuery.reconnect !== "undefined") {
+  options.reconnect = Number(parsedResourceQuery.reconnect);
+}
+
+/**
+ * @param {string} level
+ */
+function setAllLogLevel(level) {
+  // This is needed because the HMR logger operate separately from dev server logger
+  webpackHotLog.setLogLevel(level === "verbose" || level === "log" ? "info" : level);
+  setLogLevel(level);
+}
+if (options.logging) {
+  setAllLogLevel(options.logging);
+}
+logEnabledFeatures(enabledFeatures);
+self.addEventListener("beforeunload", function () {
+  status.isUnloading = true;
+});
+var overlay = typeof window !== "undefined" ? createOverlay(typeof options.overlay === "object" ? {
+  trustedTypesPolicyName: options.overlay.trustedTypesPolicyName,
+  catchRuntimeError: options.overlay.runtimeErrors
+} : {
+  trustedTypesPolicyName: false,
+  catchRuntimeError: options.overlay
+}) : {
+  send: function send() {}
+};
+var onSocketMessage = {
+  hot: function hot() {
+    if (parsedResourceQuery.hot === "false") {
+      return;
+    }
+    options.hot = true;
+  },
+  liveReload: function liveReload() {
+    if (parsedResourceQuery["live-reload"] === "false") {
+      return;
+    }
+    options.liveReload = true;
+  },
+  invalid: function invalid() {
+    log.info("App updated. Recompiling...");
+
+    // Fixes #1042. overlay doesn't clear if errors are fixed but warnings remain.
+    if (options.overlay) {
+      overlay.send({
+        type: "DISMISS"
+      });
+    }
+    sendMessage("Invalid");
+  },
+  /**
+   * @param {string} hash
+   */
+  hash: function hash(_hash) {
+    status.previousHash = status.currentHash;
+    status.currentHash = _hash;
+  },
+  logging: setAllLogLevel,
+  /**
+   * @param {boolean} value
+   */
+  overlay: function overlay(value) {
+    if (typeof document === "undefined") {
+      return;
+    }
+    options.overlay = value;
+    decodeOverlayOptions(options.overlay);
+  },
+  /**
+   * @param {number} value
+   */
+  reconnect: function reconnect(value) {
+    if (parsedResourceQuery.reconnect === "false") {
+      return;
+    }
+    options.reconnect = value;
+  },
+  /**
+   * @param {boolean} value
+   */
+  progress: function progress(value) {
+    options.progress = value;
+  },
+  /**
+   * @param {{ pluginName?: string, percent: number, msg: string }} data
+   */
+  "progress-update": function progressUpdate(data) {
+    if (options.progress) {
+      log.info("".concat(data.pluginName ? "[".concat(data.pluginName, "] ") : "").concat(data.percent, "% - ").concat(data.msg, "."));
+    }
+    sendMessage("Progress", data);
+  },
+  "still-ok": function stillOk() {
+    log.info("Nothing changed.");
+    if (options.overlay) {
+      overlay.send({
+        type: "DISMISS"
+      });
+    }
+    sendMessage("StillOk");
+  },
+  ok: function ok() {
+    sendMessage("Ok");
+    if (options.overlay) {
+      overlay.send({
+        type: "DISMISS"
+      });
+    }
+    reloadApp(options, status);
+  },
+  // TODO: remove in v5 in favor of 'static-changed'
+  /**
+   * @param {string} file
+   */
+  "content-changed": function contentChanged(file) {
+    log.info("".concat(file ? "\"".concat(file, "\"") : "Content", " from static directory was changed. Reloading..."));
+    self.location.reload();
+  },
+  /**
+   * @param {string} file
+   */
+  "static-changed": function staticChanged(file) {
+    log.info("".concat(file ? "\"".concat(file, "\"") : "Content", " from static directory was changed. Reloading..."));
+    self.location.reload();
+  },
+  /**
+   * @param {Error[]} warnings
+   * @param {any} params
+   */
+  warnings: function warnings(_warnings, params) {
+    log.warn("Warnings while compiling.");
+    var printableWarnings = _warnings.map(function (error) {
+      var _formatProblem = formatProblem("warning", error),
+        header = _formatProblem.header,
+        body = _formatProblem.body;
+      return "".concat(header, "\n").concat(stripAnsi(body));
+    });
+    sendMessage("Warnings", printableWarnings);
+    for (var i = 0; i < printableWarnings.length; i++) {
+      log.warn(printableWarnings[i]);
+    }
+    var overlayWarningsSetting = typeof options.overlay === "boolean" ? options.overlay : options.overlay && options.overlay.warnings;
+    if (overlayWarningsSetting) {
+      var warningsToDisplay = typeof overlayWarningsSetting === "function" ? _warnings.filter(overlayWarningsSetting) : _warnings;
+      if (warningsToDisplay.length) {
+        overlay.send({
+          type: "BUILD_ERROR",
+          level: "warning",
+          messages: _warnings
+        });
+      }
+    }
+    if (params && params.preventReloading) {
+      return;
+    }
+    reloadApp(options, status);
+  },
+  /**
+   * @param {Error[]} errors
+   */
+  errors: function errors(_errors) {
+    log.error("Errors while compiling. Reload prevented.");
+    var printableErrors = _errors.map(function (error) {
+      var _formatProblem2 = formatProblem("error", error),
+        header = _formatProblem2.header,
+        body = _formatProblem2.body;
+      return "".concat(header, "\n").concat(stripAnsi(body));
+    });
+    sendMessage("Errors", printableErrors);
+    for (var i = 0; i < printableErrors.length; i++) {
+      log.error(printableErrors[i]);
+    }
+    var overlayErrorsSettings = typeof options.overlay === "boolean" ? options.overlay : options.overlay && options.overlay.errors;
+    if (overlayErrorsSettings) {
+      var errorsToDisplay = typeof overlayErrorsSettings === "function" ? _errors.filter(overlayErrorsSettings) : _errors;
+      if (errorsToDisplay.length) {
+        overlay.send({
+          type: "BUILD_ERROR",
+          level: "error",
+          messages: _errors
+        });
+      }
+    }
+  },
+  /**
+   * @param {Error} error
+   */
+  error: function error(_error) {
+    log.error(_error);
+  },
+  close: function close() {
+    log.info("Disconnected!");
+    if (options.overlay) {
+      overlay.send({
+        type: "DISMISS"
+      });
+    }
+    sendMessage("Close");
+  }
+};
+var socketURL = createSocketURL(parsedResourceQuery);
+socket(socketURL, onSocketMessage, options.reconnect);
Index: frontend/node_modules/webpack-dev-server/client/modules/logger/index.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/modules/logger/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/modules/logger/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,728 @@
+/******/ (function() { // webpackBootstrap
+/******/ 	"use strict";
+/******/ 	var __webpack_modules__ = ({
+
+/***/ "./client-src/modules/logger/SyncBailHookFake.js":
+/*!*******************************************************!*\
+  !*** ./client-src/modules/logger/SyncBailHookFake.js ***!
+  \*******************************************************/
+/***/ (function(module) {
+
+
+
+/**
+ * Client stub for tapable SyncBailHook
+ */
+module.exports = function clientTapableSyncBailHook() {
+  return {
+    call: function call() {}
+  };
+};
+
+/***/ }),
+
+/***/ "./node_modules/webpack/lib/logging/Logger.js":
+/*!****************************************************!*\
+  !*** ./node_modules/webpack/lib/logging/Logger.js ***!
+  \****************************************************/
+/***/ (function(__unused_webpack_module, exports) {
+
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+
+
+
+function _toConsumableArray(arr) {
+  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
+}
+function _nonIterableSpread() {
+  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+function _unsupportedIterableToArray(o, minLen) {
+  if (!o) return;
+  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
+  var n = Object.prototype.toString.call(o).slice(8, -1);
+  if (n === "Object" && o.constructor) n = o.constructor.name;
+  if (n === "Map" || n === "Set") return Array.from(o);
+  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
+}
+function _iterableToArray(iter) {
+  if (typeof (typeof Symbol !== "undefined" ? Symbol : function (i) { return i; }) !== "undefined" && iter[(typeof Symbol !== "undefined" ? Symbol : function (i) { return i; }).iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
+}
+function _arrayWithoutHoles(arr) {
+  if (Array.isArray(arr)) return _arrayLikeToArray(arr);
+}
+function _arrayLikeToArray(arr, len) {
+  if (len == null || len > arr.length) len = arr.length;
+  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
+  return arr2;
+}
+function _classCallCheck(instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+}
+function _defineProperties(target, props) {
+  for (var i = 0; i < props.length; i++) {
+    var descriptor = props[i];
+    descriptor.enumerable = descriptor.enumerable || false;
+    descriptor.configurable = true;
+    if ("value" in descriptor) descriptor.writable = true;
+    Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
+  }
+}
+function _createClass(Constructor, protoProps, staticProps) {
+  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+  if (staticProps) _defineProperties(Constructor, staticProps);
+  Object.defineProperty(Constructor, "prototype", {
+    writable: false
+  });
+  return Constructor;
+}
+function _toPropertyKey(arg) {
+  var key = _toPrimitive(arg, "string");
+  return typeof key === "symbol" ? key : String(key);
+}
+function _toPrimitive(input, hint) {
+  if (typeof input !== "object" || input === null) return input;
+  var prim = input[(typeof Symbol !== "undefined" ? Symbol : function (i) { return i; }).toPrimitive];
+  if (prim !== undefined) {
+    var res = prim.call(input, hint || "default");
+    if (typeof res !== "object") return res;
+    throw new TypeError("@@toPrimitive must return a primitive value.");
+  }
+  return (hint === "string" ? String : Number)(input);
+}
+var LogType = Object.freeze({
+  error: /** @type {"error"} */"error",
+  // message, c style arguments
+  warn: /** @type {"warn"} */"warn",
+  // message, c style arguments
+  info: /** @type {"info"} */"info",
+  // message, c style arguments
+  log: /** @type {"log"} */"log",
+  // message, c style arguments
+  debug: /** @type {"debug"} */"debug",
+  // message, c style arguments
+
+  trace: /** @type {"trace"} */"trace",
+  // no arguments
+
+  group: /** @type {"group"} */"group",
+  // [label]
+  groupCollapsed: /** @type {"groupCollapsed"} */"groupCollapsed",
+  // [label]
+  groupEnd: /** @type {"groupEnd"} */"groupEnd",
+  // [label]
+
+  profile: /** @type {"profile"} */"profile",
+  // [profileName]
+  profileEnd: /** @type {"profileEnd"} */"profileEnd",
+  // [profileName]
+
+  time: /** @type {"time"} */"time",
+  // name, time as [seconds, nanoseconds]
+
+  clear: /** @type {"clear"} */"clear",
+  // no arguments
+  status: /** @type {"status"} */"status" // message, arguments
+});
+
+exports.LogType = LogType;
+
+/** @typedef {typeof LogType[keyof typeof LogType]} LogTypeEnum */
+
+var LOG_SYMBOL = (typeof Symbol !== "undefined" ? Symbol : function (i) { return i; })("webpack logger raw log method");
+var TIMERS_SYMBOL = (typeof Symbol !== "undefined" ? Symbol : function (i) { return i; })("webpack logger times");
+var TIMERS_AGGREGATES_SYMBOL = (typeof Symbol !== "undefined" ? Symbol : function (i) { return i; })("webpack logger aggregated times");
+var WebpackLogger = /*#__PURE__*/function () {
+  /**
+   * @param {function(LogTypeEnum, any[]=): void} log log function
+   * @param {function(string | function(): string): WebpackLogger} getChildLogger function to create child logger
+   */
+  function WebpackLogger(log, getChildLogger) {
+    _classCallCheck(this, WebpackLogger);
+    this[LOG_SYMBOL] = log;
+    this.getChildLogger = getChildLogger;
+  }
+  _createClass(WebpackLogger, [{
+    key: "error",
+    value: function error() {
+      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+        args[_key] = arguments[_key];
+      }
+      this[LOG_SYMBOL](LogType.error, args);
+    }
+  }, {
+    key: "warn",
+    value: function warn() {
+      for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+        args[_key2] = arguments[_key2];
+      }
+      this[LOG_SYMBOL](LogType.warn, args);
+    }
+  }, {
+    key: "info",
+    value: function info() {
+      for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
+        args[_key3] = arguments[_key3];
+      }
+      this[LOG_SYMBOL](LogType.info, args);
+    }
+  }, {
+    key: "log",
+    value: function log() {
+      for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
+        args[_key4] = arguments[_key4];
+      }
+      this[LOG_SYMBOL](LogType.log, args);
+    }
+  }, {
+    key: "debug",
+    value: function debug() {
+      for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
+        args[_key5] = arguments[_key5];
+      }
+      this[LOG_SYMBOL](LogType.debug, args);
+    }
+  }, {
+    key: "assert",
+    value: function assert(assertion) {
+      if (!assertion) {
+        for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
+          args[_key6 - 1] = arguments[_key6];
+        }
+        this[LOG_SYMBOL](LogType.error, args);
+      }
+    }
+  }, {
+    key: "trace",
+    value: function trace() {
+      this[LOG_SYMBOL](LogType.trace, ["Trace"]);
+    }
+  }, {
+    key: "clear",
+    value: function clear() {
+      this[LOG_SYMBOL](LogType.clear);
+    }
+  }, {
+    key: "status",
+    value: function status() {
+      for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) {
+        args[_key7] = arguments[_key7];
+      }
+      this[LOG_SYMBOL](LogType.status, args);
+    }
+  }, {
+    key: "group",
+    value: function group() {
+      for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) {
+        args[_key8] = arguments[_key8];
+      }
+      this[LOG_SYMBOL](LogType.group, args);
+    }
+  }, {
+    key: "groupCollapsed",
+    value: function groupCollapsed() {
+      for (var _len9 = arguments.length, args = new Array(_len9), _key9 = 0; _key9 < _len9; _key9++) {
+        args[_key9] = arguments[_key9];
+      }
+      this[LOG_SYMBOL](LogType.groupCollapsed, args);
+    }
+  }, {
+    key: "groupEnd",
+    value: function groupEnd() {
+      for (var _len10 = arguments.length, args = new Array(_len10), _key10 = 0; _key10 < _len10; _key10++) {
+        args[_key10] = arguments[_key10];
+      }
+      this[LOG_SYMBOL](LogType.groupEnd, args);
+    }
+  }, {
+    key: "profile",
+    value: function profile(label) {
+      this[LOG_SYMBOL](LogType.profile, [label]);
+    }
+  }, {
+    key: "profileEnd",
+    value: function profileEnd(label) {
+      this[LOG_SYMBOL](LogType.profileEnd, [label]);
+    }
+  }, {
+    key: "time",
+    value: function time(label) {
+      this[TIMERS_SYMBOL] = this[TIMERS_SYMBOL] || new Map();
+      this[TIMERS_SYMBOL].set(label, process.hrtime());
+    }
+  }, {
+    key: "timeLog",
+    value: function timeLog(label) {
+      var prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label);
+      if (!prev) {
+        throw new Error("No such label '".concat(label, "' for WebpackLogger.timeLog()"));
+      }
+      var time = process.hrtime(prev);
+      this[LOG_SYMBOL](LogType.time, [label].concat(_toConsumableArray(time)));
+    }
+  }, {
+    key: "timeEnd",
+    value: function timeEnd(label) {
+      var prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label);
+      if (!prev) {
+        throw new Error("No such label '".concat(label, "' for WebpackLogger.timeEnd()"));
+      }
+      var time = process.hrtime(prev);
+      this[TIMERS_SYMBOL].delete(label);
+      this[LOG_SYMBOL](LogType.time, [label].concat(_toConsumableArray(time)));
+    }
+  }, {
+    key: "timeAggregate",
+    value: function timeAggregate(label) {
+      var prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label);
+      if (!prev) {
+        throw new Error("No such label '".concat(label, "' for WebpackLogger.timeAggregate()"));
+      }
+      var time = process.hrtime(prev);
+      this[TIMERS_SYMBOL].delete(label);
+      this[TIMERS_AGGREGATES_SYMBOL] = this[TIMERS_AGGREGATES_SYMBOL] || new Map();
+      var current = this[TIMERS_AGGREGATES_SYMBOL].get(label);
+      if (current !== undefined) {
+        if (time[1] + current[1] > 1e9) {
+          time[0] += current[0] + 1;
+          time[1] = time[1] - 1e9 + current[1];
+        } else {
+          time[0] += current[0];
+          time[1] += current[1];
+        }
+      }
+      this[TIMERS_AGGREGATES_SYMBOL].set(label, time);
+    }
+  }, {
+    key: "timeAggregateEnd",
+    value: function timeAggregateEnd(label) {
+      if (this[TIMERS_AGGREGATES_SYMBOL] === undefined) return;
+      var time = this[TIMERS_AGGREGATES_SYMBOL].get(label);
+      if (time === undefined) return;
+      this[TIMERS_AGGREGATES_SYMBOL].delete(label);
+      this[LOG_SYMBOL](LogType.time, [label].concat(_toConsumableArray(time)));
+    }
+  }]);
+  return WebpackLogger;
+}();
+exports.Logger = WebpackLogger;
+
+/***/ }),
+
+/***/ "./node_modules/webpack/lib/logging/createConsoleLogger.js":
+/*!*****************************************************************!*\
+  !*** ./node_modules/webpack/lib/logging/createConsoleLogger.js ***!
+  \*****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+
+
+
+function _toConsumableArray(arr) {
+  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
+}
+function _nonIterableSpread() {
+  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+function _unsupportedIterableToArray(o, minLen) {
+  if (!o) return;
+  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
+  var n = Object.prototype.toString.call(o).slice(8, -1);
+  if (n === "Object" && o.constructor) n = o.constructor.name;
+  if (n === "Map" || n === "Set") return Array.from(o);
+  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
+}
+function _iterableToArray(iter) {
+  if (typeof (typeof Symbol !== "undefined" ? Symbol : function (i) { return i; }) !== "undefined" && iter[(typeof Symbol !== "undefined" ? Symbol : function (i) { return i; }).iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
+}
+function _arrayWithoutHoles(arr) {
+  if (Array.isArray(arr)) return _arrayLikeToArray(arr);
+}
+function _arrayLikeToArray(arr, len) {
+  if (len == null || len > arr.length) len = arr.length;
+  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
+  return arr2;
+}
+var _require = __webpack_require__(/*! ./Logger */ "./node_modules/webpack/lib/logging/Logger.js"),
+  LogType = _require.LogType;
+
+/** @typedef {import("../../declarations/WebpackOptions").FilterItemTypes} FilterItemTypes */
+/** @typedef {import("../../declarations/WebpackOptions").FilterTypes} FilterTypes */
+/** @typedef {import("./Logger").LogTypeEnum} LogTypeEnum */
+
+/** @typedef {function(string): boolean} FilterFunction */
+
+/**
+ * @typedef {Object} LoggerConsole
+ * @property {function(): void} clear
+ * @property {function(): void} trace
+ * @property {(...args: any[]) => void} info
+ * @property {(...args: any[]) => void} log
+ * @property {(...args: any[]) => void} warn
+ * @property {(...args: any[]) => void} error
+ * @property {(...args: any[]) => void=} debug
+ * @property {(...args: any[]) => void=} group
+ * @property {(...args: any[]) => void=} groupCollapsed
+ * @property {(...args: any[]) => void=} groupEnd
+ * @property {(...args: any[]) => void=} status
+ * @property {(...args: any[]) => void=} profile
+ * @property {(...args: any[]) => void=} profileEnd
+ * @property {(...args: any[]) => void=} logTime
+ */
+
+/**
+ * @typedef {Object} LoggerOptions
+ * @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} level loglevel
+ * @property {FilterTypes|boolean} debug filter for debug logging
+ * @property {LoggerConsole} console the console to log to
+ */
+
+/**
+ * @param {FilterItemTypes} item an input item
+ * @returns {FilterFunction} filter function
+ */
+var filterToFunction = function filterToFunction(item) {
+  if (typeof item === "string") {
+    var regExp = new RegExp("[\\\\/]".concat(item.replace(
+    // eslint-disable-next-line no-useless-escape
+    /[-[\]{}()*+?.\\^$|]/g, "\\$&"), "([\\\\/]|$|!|\\?)"));
+    return function (ident) {
+      return regExp.test(ident);
+    };
+  }
+  if (item && typeof item === "object" && typeof item.test === "function") {
+    return function (ident) {
+      return item.test(ident);
+    };
+  }
+  if (typeof item === "function") {
+    return item;
+  }
+  if (typeof item === "boolean") {
+    return function () {
+      return item;
+    };
+  }
+};
+
+/**
+ * @enum {number}
+ */
+var LogLevel = {
+  none: 6,
+  false: 6,
+  error: 5,
+  warn: 4,
+  info: 3,
+  log: 2,
+  true: 2,
+  verbose: 1
+};
+
+/**
+ * @param {LoggerOptions} options options object
+ * @returns {function(string, LogTypeEnum, any[]): void} logging function
+ */
+module.exports = function (_ref) {
+  var _ref$level = _ref.level,
+    level = _ref$level === void 0 ? "info" : _ref$level,
+    _ref$debug = _ref.debug,
+    debug = _ref$debug === void 0 ? false : _ref$debug,
+    console = _ref.console;
+  var debugFilters = typeof debug === "boolean" ? [function () {
+    return debug;
+  }] : /** @type {FilterItemTypes[]} */[].concat(debug).map(filterToFunction);
+  /** @type {number} */
+  var loglevel = LogLevel["".concat(level)] || 0;
+
+  /**
+   * @param {string} name name of the logger
+   * @param {LogTypeEnum} type type of the log entry
+   * @param {any[]} args arguments of the log entry
+   * @returns {void}
+   */
+  var logger = function logger(name, type, args) {
+    var labeledArgs = function labeledArgs() {
+      if (Array.isArray(args)) {
+        if (args.length > 0 && typeof args[0] === "string") {
+          return ["[".concat(name, "] ").concat(args[0])].concat(_toConsumableArray(args.slice(1)));
+        } else {
+          return ["[".concat(name, "]")].concat(_toConsumableArray(args));
+        }
+      } else {
+        return [];
+      }
+    };
+    var debug = debugFilters.some(function (f) {
+      return f(name);
+    });
+    switch (type) {
+      case LogType.debug:
+        if (!debug) return;
+        // eslint-disable-next-line node/no-unsupported-features/node-builtins
+        if (typeof console.debug === "function") {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          console.debug.apply(console, _toConsumableArray(labeledArgs()));
+        } else {
+          console.log.apply(console, _toConsumableArray(labeledArgs()));
+        }
+        break;
+      case LogType.log:
+        if (!debug && loglevel > LogLevel.log) return;
+        console.log.apply(console, _toConsumableArray(labeledArgs()));
+        break;
+      case LogType.info:
+        if (!debug && loglevel > LogLevel.info) return;
+        console.info.apply(console, _toConsumableArray(labeledArgs()));
+        break;
+      case LogType.warn:
+        if (!debug && loglevel > LogLevel.warn) return;
+        console.warn.apply(console, _toConsumableArray(labeledArgs()));
+        break;
+      case LogType.error:
+        if (!debug && loglevel > LogLevel.error) return;
+        console.error.apply(console, _toConsumableArray(labeledArgs()));
+        break;
+      case LogType.trace:
+        if (!debug) return;
+        console.trace();
+        break;
+      case LogType.groupCollapsed:
+        if (!debug && loglevel > LogLevel.log) return;
+        if (!debug && loglevel > LogLevel.verbose) {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          if (typeof console.groupCollapsed === "function") {
+            // eslint-disable-next-line node/no-unsupported-features/node-builtins
+            console.groupCollapsed.apply(console, _toConsumableArray(labeledArgs()));
+          } else {
+            console.log.apply(console, _toConsumableArray(labeledArgs()));
+          }
+          break;
+        }
+      // falls through
+      case LogType.group:
+        if (!debug && loglevel > LogLevel.log) return;
+        // eslint-disable-next-line node/no-unsupported-features/node-builtins
+        if (typeof console.group === "function") {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          console.group.apply(console, _toConsumableArray(labeledArgs()));
+        } else {
+          console.log.apply(console, _toConsumableArray(labeledArgs()));
+        }
+        break;
+      case LogType.groupEnd:
+        if (!debug && loglevel > LogLevel.log) return;
+        // eslint-disable-next-line node/no-unsupported-features/node-builtins
+        if (typeof console.groupEnd === "function") {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          console.groupEnd();
+        }
+        break;
+      case LogType.time:
+        {
+          if (!debug && loglevel > LogLevel.log) return;
+          var ms = args[1] * 1000 + args[2] / 1000000;
+          var msg = "[".concat(name, "] ").concat(args[0], ": ").concat(ms, " ms");
+          if (typeof console.logTime === "function") {
+            console.logTime(msg);
+          } else {
+            console.log(msg);
+          }
+          break;
+        }
+      case LogType.profile:
+        // eslint-disable-next-line node/no-unsupported-features/node-builtins
+        if (typeof console.profile === "function") {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          console.profile.apply(console, _toConsumableArray(labeledArgs()));
+        }
+        break;
+      case LogType.profileEnd:
+        // eslint-disable-next-line node/no-unsupported-features/node-builtins
+        if (typeof console.profileEnd === "function") {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          console.profileEnd.apply(console, _toConsumableArray(labeledArgs()));
+        }
+        break;
+      case LogType.clear:
+        if (!debug && loglevel > LogLevel.log) return;
+        // eslint-disable-next-line node/no-unsupported-features/node-builtins
+        if (typeof console.clear === "function") {
+          // eslint-disable-next-line node/no-unsupported-features/node-builtins
+          console.clear();
+        }
+        break;
+      case LogType.status:
+        if (!debug && loglevel > LogLevel.info) return;
+        if (typeof console.status === "function") {
+          if (args.length === 0) {
+            console.status();
+          } else {
+            console.status.apply(console, _toConsumableArray(labeledArgs()));
+          }
+        } else {
+          if (args.length !== 0) {
+            console.info.apply(console, _toConsumableArray(labeledArgs()));
+          }
+        }
+        break;
+      default:
+        throw new Error("Unexpected LogType ".concat(type));
+    }
+  };
+  return logger;
+};
+
+/***/ }),
+
+/***/ "./node_modules/webpack/lib/logging/runtime.js":
+/*!*****************************************************!*\
+  !*** ./node_modules/webpack/lib/logging/runtime.js ***!
+  \*****************************************************/
+/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
+
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+
+
+
+function _extends() {
+  _extends = Object.assign ? Object.assign.bind() : function (target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i];
+      for (var key in source) {
+        if (Object.prototype.hasOwnProperty.call(source, key)) {
+          target[key] = source[key];
+        }
+      }
+    }
+    return target;
+  };
+  return _extends.apply(this, arguments);
+}
+var SyncBailHook = __webpack_require__(/*! tapable/lib/SyncBailHook */ "./client-src/modules/logger/SyncBailHookFake.js");
+var _require = __webpack_require__(/*! ./Logger */ "./node_modules/webpack/lib/logging/Logger.js"),
+  Logger = _require.Logger;
+var createConsoleLogger = __webpack_require__(/*! ./createConsoleLogger */ "./node_modules/webpack/lib/logging/createConsoleLogger.js");
+
+/** @type {createConsoleLogger.LoggerOptions} */
+var currentDefaultLoggerOptions = {
+  level: "info",
+  debug: false,
+  console: console
+};
+var currentDefaultLogger = createConsoleLogger(currentDefaultLoggerOptions);
+
+/**
+ * @param {string} name name of the logger
+ * @returns {Logger} a logger
+ */
+exports.getLogger = function (name) {
+  return new Logger(function (type, args) {
+    if (exports.hooks.log.call(name, type, args) === undefined) {
+      currentDefaultLogger(name, type, args);
+    }
+  }, function (childName) {
+    return exports.getLogger("".concat(name, "/").concat(childName));
+  });
+};
+
+/**
+ * @param {createConsoleLogger.LoggerOptions} options new options, merge with old options
+ * @returns {void}
+ */
+exports.configureDefaultLogger = function (options) {
+  _extends(currentDefaultLoggerOptions, options);
+  currentDefaultLogger = createConsoleLogger(currentDefaultLoggerOptions);
+};
+exports.hooks = {
+  log: new SyncBailHook(["origin", "type", "args"])
+};
+
+/***/ })
+
+/******/ 	});
+/************************************************************************/
+/******/ 	// The module cache
+/******/ 	var __webpack_module_cache__ = {};
+/******/ 	
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/ 		// Check if module is in cache
+/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
+/******/ 		if (cachedModule !== undefined) {
+/******/ 			return cachedModule.exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = __webpack_module_cache__[moduleId] = {
+/******/ 			// no module.id needed
+/******/ 			// no module.loaded needed
+/******/ 			exports: {}
+/******/ 		};
+/******/ 	
+/******/ 		// Execute the module function
+/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/ 	
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/ 	
+/************************************************************************/
+/******/ 	/* webpack/runtime/define property getters */
+/******/ 	!function() {
+/******/ 		// define getter functions for harmony exports
+/******/ 		__webpack_require__.d = function(exports, definition) {
+/******/ 			for(var key in definition) {
+/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ 				}
+/******/ 			}
+/******/ 		};
+/******/ 	}();
+/******/ 	
+/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
+/******/ 	!function() {
+/******/ 		__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
+/******/ 	}();
+/******/ 	
+/******/ 	/* webpack/runtime/make namespace object */
+/******/ 	!function() {
+/******/ 		// define __esModule on exports
+/******/ 		__webpack_require__.r = function(exports) {
+/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ 			}
+/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
+/******/ 		};
+/******/ 	}();
+/******/ 	
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
+!function() {
+/*!********************************************!*\
+  !*** ./client-src/modules/logger/index.js ***!
+  \********************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */   "default": function() { return /* reexport default export from named module */ webpack_lib_logging_runtime_js__WEBPACK_IMPORTED_MODULE_0__; }
+/* harmony export */ });
+/* harmony import */ var webpack_lib_logging_runtime_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! webpack/lib/logging/runtime.js */ "./node_modules/webpack/lib/logging/runtime.js");
+
+}();
+var __webpack_export_target__ = exports;
+for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i];
+if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });
+/******/ })()
+;
Index: frontend/node_modules/webpack-dev-server/client/modules/sockjs-client/index.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/modules/sockjs-client/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/modules/sockjs-client/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,5039 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+	if(typeof exports === 'object' && typeof module === 'object')
+		module.exports = factory();
+	else if(typeof define === 'function' && define.amd)
+		define([], factory);
+	else if(typeof exports === 'object')
+		exports["SockJS"] = factory();
+	else
+		root["SockJS"] = factory();
+})((typeof self !== 'undefined' ? self : this), function() {
+return /******/ (function() { // webpackBootstrap
+/******/ 	var __webpack_modules__ = ({
+
+/***/ "./node_modules/inherits/inherits_browser.js":
+/*!***************************************************!*\
+  !*** ./node_modules/inherits/inherits_browser.js ***!
+  \***************************************************/
+/***/ (function(module) {
+
+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() {};
+      TempCtor.prototype = superCtor.prototype;
+      ctor.prototype = new TempCtor();
+      ctor.prototype.constructor = ctor;
+    }
+  };
+}
+
+/***/ }),
+
+/***/ "./node_modules/ms/index.js":
+/*!**********************************!*\
+  !*** ./node_modules/ms/index.js ***!
+  \**********************************/
+/***/ (function(module) {
+
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var w = d * 7;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ *  - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} [options]
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function (val, options) {
+  options = options || {};
+  var type = typeof val;
+  if (type === 'string' && val.length > 0) {
+    return parse(val);
+  } else if (type === 'number' && isFinite(val)) {
+    return options.long ? fmtLong(val) : fmtShort(val);
+  }
+  throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val));
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  str = String(str);
+  if (str.length > 100) {
+    return;
+  }
+  var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);
+  if (!match) {
+    return;
+  }
+  var n = parseFloat(match[1]);
+  var type = (match[2] || 'ms').toLowerCase();
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'yrs':
+    case 'yr':
+    case 'y':
+      return n * y;
+    case 'weeks':
+    case 'week':
+    case 'w':
+      return n * w;
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * d;
+    case 'hours':
+    case 'hour':
+    case 'hrs':
+    case 'hr':
+    case 'h':
+      return n * h;
+    case 'minutes':
+    case 'minute':
+    case 'mins':
+    case 'min':
+    case 'm':
+      return n * m;
+    case 'seconds':
+    case 'second':
+    case 'secs':
+    case 'sec':
+    case 's':
+      return n * s;
+    case 'milliseconds':
+    case 'millisecond':
+    case 'msecs':
+    case 'msec':
+    case 'ms':
+      return n;
+    default:
+      return undefined;
+  }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+  var msAbs = Math.abs(ms);
+  if (msAbs >= d) {
+    return Math.round(ms / d) + 'd';
+  }
+  if (msAbs >= h) {
+    return Math.round(ms / h) + 'h';
+  }
+  if (msAbs >= m) {
+    return Math.round(ms / m) + 'm';
+  }
+  if (msAbs >= s) {
+    return Math.round(ms / s) + 's';
+  }
+  return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+  var msAbs = Math.abs(ms);
+  if (msAbs >= d) {
+    return plural(ms, msAbs, d, 'day');
+  }
+  if (msAbs >= h) {
+    return plural(ms, msAbs, h, 'hour');
+  }
+  if (msAbs >= m) {
+    return plural(ms, msAbs, m, 'minute');
+  }
+  if (msAbs >= s) {
+    return plural(ms, msAbs, s, 'second');
+  }
+  return ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, msAbs, n, name) {
+  var isPlural = msAbs >= n * 1.5;
+  return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
+}
+
+/***/ }),
+
+/***/ "./node_modules/querystringify/index.js":
+/*!**********************************************!*\
+  !*** ./node_modules/querystringify/index.js ***!
+  \**********************************************/
+/***/ (function(__unused_webpack_module, exports) {
+
+"use strict";
+
+
+var has = Object.prototype.hasOwnProperty,
+  undef;
+
+/**
+ * Decode a URI encoded string.
+ *
+ * @param {String} input The URI encoded string.
+ * @returns {String|Null} The decoded string.
+ * @api private
+ */
+function decode(input) {
+  try {
+    return decodeURIComponent(input.replace(/\+/g, ' '));
+  } catch (e) {
+    return null;
+  }
+}
+
+/**
+ * Attempts to encode a given input.
+ *
+ * @param {String} input The string that needs to be encoded.
+ * @returns {String|Null} The encoded string.
+ * @api private
+ */
+function encode(input) {
+  try {
+    return encodeURIComponent(input);
+  } catch (e) {
+    return null;
+  }
+}
+
+/**
+ * Simple query string parser.
+ *
+ * @param {String} query The query string that needs to be parsed.
+ * @returns {Object}
+ * @api public
+ */
+function querystring(query) {
+  var parser = /([^=?#&]+)=?([^&]*)/g,
+    result = {},
+    part;
+  while (part = parser.exec(query)) {
+    var key = decode(part[1]),
+      value = decode(part[2]);
+
+    //
+    // Prevent overriding of existing properties. This ensures that build-in
+    // methods like `toString` or __proto__ are not overriden by malicious
+    // querystrings.
+    //
+    // In the case if failed decoding, we want to omit the key/value pairs
+    // from the result.
+    //
+    if (key === null || value === null || key in result) continue;
+    result[key] = value;
+  }
+  return result;
+}
+
+/**
+ * Transform a query string to an object.
+ *
+ * @param {Object} obj Object that should be transformed.
+ * @param {String} prefix Optional prefix.
+ * @returns {String}
+ * @api public
+ */
+function querystringify(obj, prefix) {
+  prefix = prefix || '';
+  var pairs = [],
+    value,
+    key;
+
+  //
+  // Optionally prefix with a '?' if needed
+  //
+  if ('string' !== typeof prefix) prefix = '?';
+  for (key in obj) {
+    if (has.call(obj, key)) {
+      value = obj[key];
+
+      //
+      // Edge cases where we actually want to encode the value to an empty
+      // string instead of the stringified value.
+      //
+      if (!value && (value === null || value === undef || isNaN(value))) {
+        value = '';
+      }
+      key = encode(key);
+      value = encode(value);
+
+      //
+      // If we failed to encode the strings, we should bail out as we don't
+      // want to add invalid strings to the query.
+      //
+      if (key === null || value === null) continue;
+      pairs.push(key + '=' + value);
+    }
+  }
+  return pairs.length ? prefix + pairs.join('&') : '';
+}
+
+//
+// Expose the module.
+//
+exports.stringify = querystringify;
+exports.parse = querystring;
+
+/***/ }),
+
+/***/ "./node_modules/requires-port/index.js":
+/*!*********************************************!*\
+  !*** ./node_modules/requires-port/index.js ***!
+  \*********************************************/
+/***/ (function(module) {
+
+"use strict";
+
+
+/**
+ * Check if we're required to add a port number.
+ *
+ * @see https://url.spec.whatwg.org/#default-port
+ * @param {Number|String} port Port number we need to check
+ * @param {String} protocol Protocol we need to check against.
+ * @returns {Boolean} Is it a default port for the given protocol
+ * @api private
+ */
+module.exports = function required(port, protocol) {
+  protocol = protocol.split(':')[0];
+  port = +port;
+  if (!port) return false;
+  switch (protocol) {
+    case 'http':
+    case 'ws':
+      return port !== 80;
+    case 'https':
+    case 'wss':
+      return port !== 443;
+    case 'ftp':
+      return port !== 21;
+    case 'gopher':
+      return port !== 70;
+    case 'file':
+      return false;
+  }
+  return port !== 0;
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/entry.js":
+/*!*************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/entry.js ***!
+  \*************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var transportList = __webpack_require__(/*! ./transport-list */ "./node_modules/sockjs-client/lib/transport-list.js");
+module.exports = __webpack_require__(/*! ./main */ "./node_modules/sockjs-client/lib/main.js")(transportList);
+
+// TODO can't get rid of this until all servers do
+if ('_sockjs_onload' in __webpack_require__.g) {
+  setTimeout(__webpack_require__.g._sockjs_onload, 1);
+}
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/event/close.js":
+/*!*******************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/event/close.js ***!
+  \*******************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  Event = __webpack_require__(/*! ./event */ "./node_modules/sockjs-client/lib/event/event.js");
+function CloseEvent() {
+  Event.call(this);
+  this.initEvent('close', false, false);
+  this.wasClean = false;
+  this.code = 0;
+  this.reason = '';
+}
+inherits(CloseEvent, Event);
+module.exports = CloseEvent;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/event/emitter.js":
+/*!*********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/event/emitter.js ***!
+  \*********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventTarget = __webpack_require__(/*! ./eventtarget */ "./node_modules/sockjs-client/lib/event/eventtarget.js");
+function EventEmitter() {
+  EventTarget.call(this);
+}
+inherits(EventEmitter, EventTarget);
+EventEmitter.prototype.removeAllListeners = function (type) {
+  if (type) {
+    delete this._listeners[type];
+  } else {
+    this._listeners = {};
+  }
+};
+EventEmitter.prototype.once = function (type, listener) {
+  var self = this,
+    fired = false;
+  function g() {
+    self.removeListener(type, g);
+    if (!fired) {
+      fired = true;
+      listener.apply(this, arguments);
+    }
+  }
+  this.on(type, g);
+};
+EventEmitter.prototype.emit = function () {
+  var type = arguments[0];
+  var listeners = this._listeners[type];
+  if (!listeners) {
+    return;
+  }
+  // equivalent of Array.prototype.slice.call(arguments, 1);
+  var l = arguments.length;
+  var args = new Array(l - 1);
+  for (var ai = 1; ai < l; ai++) {
+    args[ai - 1] = arguments[ai];
+  }
+  for (var i = 0; i < listeners.length; i++) {
+    listeners[i].apply(this, args);
+  }
+};
+EventEmitter.prototype.on = EventEmitter.prototype.addListener = EventTarget.prototype.addEventListener;
+EventEmitter.prototype.removeListener = EventTarget.prototype.removeEventListener;
+module.exports.EventEmitter = EventEmitter;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/event/event.js":
+/*!*******************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/event/event.js ***!
+  \*******************************************************/
+/***/ (function(module) {
+
+"use strict";
+
+
+function Event(eventType) {
+  this.type = eventType;
+}
+Event.prototype.initEvent = function (eventType, canBubble, cancelable) {
+  this.type = eventType;
+  this.bubbles = canBubble;
+  this.cancelable = cancelable;
+  this.timeStamp = +new Date();
+  return this;
+};
+Event.prototype.stopPropagation = function () {};
+Event.prototype.preventDefault = function () {};
+Event.CAPTURING_PHASE = 1;
+Event.AT_TARGET = 2;
+Event.BUBBLING_PHASE = 3;
+module.exports = Event;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/event/eventtarget.js":
+/*!*************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/event/eventtarget.js ***!
+  \*************************************************************/
+/***/ (function(module) {
+
+"use strict";
+
+
+/* Simplified implementation of DOM2 EventTarget.
+ *   http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
+ */
+function EventTarget() {
+  this._listeners = {};
+}
+EventTarget.prototype.addEventListener = function (eventType, listener) {
+  if (!(eventType in this._listeners)) {
+    this._listeners[eventType] = [];
+  }
+  var arr = this._listeners[eventType];
+  // #4
+  if (arr.indexOf(listener) === -1) {
+    // Make a copy so as not to interfere with a current dispatchEvent.
+    arr = arr.concat([listener]);
+  }
+  this._listeners[eventType] = arr;
+};
+EventTarget.prototype.removeEventListener = function (eventType, listener) {
+  var arr = this._listeners[eventType];
+  if (!arr) {
+    return;
+  }
+  var idx = arr.indexOf(listener);
+  if (idx !== -1) {
+    if (arr.length > 1) {
+      // Make a copy so as not to interfere with a current dispatchEvent.
+      this._listeners[eventType] = arr.slice(0, idx).concat(arr.slice(idx + 1));
+    } else {
+      delete this._listeners[eventType];
+    }
+    return;
+  }
+};
+EventTarget.prototype.dispatchEvent = function () {
+  var event = arguments[0];
+  var t = event.type;
+  // equivalent of Array.prototype.slice.call(arguments, 0);
+  var args = arguments.length === 1 ? [event] : Array.apply(null, arguments);
+  // TODO: This doesn't match the real behavior; per spec, onfoo get
+  // their place in line from the /first/ time they're set from
+  // non-null. Although WebKit bumps it to the end every time it's
+  // set.
+  if (this['on' + t]) {
+    this['on' + t].apply(this, args);
+  }
+  if (t in this._listeners) {
+    // Grab a reference to the listeners list. removeEventListener may alter the list.
+    var listeners = this._listeners[t];
+    for (var i = 0; i < listeners.length; i++) {
+      listeners[i].apply(this, args);
+    }
+  }
+};
+module.exports = EventTarget;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/event/trans-message.js":
+/*!***************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/event/trans-message.js ***!
+  \***************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  Event = __webpack_require__(/*! ./event */ "./node_modules/sockjs-client/lib/event/event.js");
+function TransportMessageEvent(data) {
+  Event.call(this);
+  this.initEvent('message', false, false);
+  this.data = data;
+}
+inherits(TransportMessageEvent, Event);
+module.exports = TransportMessageEvent;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/facade.js":
+/*!**************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/facade.js ***!
+  \**************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var iframeUtils = __webpack_require__(/*! ./utils/iframe */ "./node_modules/sockjs-client/lib/utils/iframe.js");
+function FacadeJS(transport) {
+  this._transport = transport;
+  transport.on('message', this._transportMessage.bind(this));
+  transport.on('close', this._transportClose.bind(this));
+}
+FacadeJS.prototype._transportClose = function (code, reason) {
+  iframeUtils.postMessage('c', JSON.stringify([code, reason]));
+};
+FacadeJS.prototype._transportMessage = function (frame) {
+  iframeUtils.postMessage('t', frame);
+};
+FacadeJS.prototype._send = function (data) {
+  this._transport.send(data);
+};
+FacadeJS.prototype._close = function () {
+  this._transport.close();
+  this._transport.removeAllListeners();
+};
+module.exports = FacadeJS;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/iframe-bootstrap.js":
+/*!************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/iframe-bootstrap.js ***!
+  \************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var urlUtils = __webpack_require__(/*! ./utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  eventUtils = __webpack_require__(/*! ./utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  FacadeJS = __webpack_require__(/*! ./facade */ "./node_modules/sockjs-client/lib/facade.js"),
+  InfoIframeReceiver = __webpack_require__(/*! ./info-iframe-receiver */ "./node_modules/sockjs-client/lib/info-iframe-receiver.js"),
+  iframeUtils = __webpack_require__(/*! ./utils/iframe */ "./node_modules/sockjs-client/lib/utils/iframe.js"),
+  loc = __webpack_require__(/*! ./location */ "./node_modules/sockjs-client/lib/location.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:iframe-bootstrap');
+}
+module.exports = function (SockJS, availableTransports) {
+  var transportMap = {};
+  availableTransports.forEach(function (at) {
+    if (at.facadeTransport) {
+      transportMap[at.facadeTransport.transportName] = at.facadeTransport;
+    }
+  });
+
+  // hard-coded for the info iframe
+  // TODO see if we can make this more dynamic
+  transportMap[InfoIframeReceiver.transportName] = InfoIframeReceiver;
+  var parentOrigin;
+
+  /* eslint-disable camelcase */
+  SockJS.bootstrap_iframe = function () {
+    /* eslint-enable camelcase */
+    var facade;
+    iframeUtils.currentWindowId = loc.hash.slice(1);
+    var onMessage = function onMessage(e) {
+      if (e.source !== parent) {
+        return;
+      }
+      if (typeof parentOrigin === 'undefined') {
+        parentOrigin = e.origin;
+      }
+      if (e.origin !== parentOrigin) {
+        return;
+      }
+      var iframeMessage;
+      try {
+        iframeMessage = JSON.parse(e.data);
+      } catch (ignored) {
+        debug('bad json', e.data);
+        return;
+      }
+      if (iframeMessage.windowId !== iframeUtils.currentWindowId) {
+        return;
+      }
+      switch (iframeMessage.type) {
+        case 's':
+          var p;
+          try {
+            p = JSON.parse(iframeMessage.data);
+          } catch (ignored) {
+            debug('bad json', iframeMessage.data);
+            break;
+          }
+          var version = p[0];
+          var transport = p[1];
+          var transUrl = p[2];
+          var baseUrl = p[3];
+          debug(version, transport, transUrl, baseUrl);
+          // change this to semver logic
+          if (version !== SockJS.version) {
+            throw new Error('Incompatible SockJS! Main site uses:' + ' "' + version + '", the iframe:' + ' "' + SockJS.version + '".');
+          }
+          if (!urlUtils.isOriginEqual(transUrl, loc.href) || !urlUtils.isOriginEqual(baseUrl, loc.href)) {
+            throw new Error('Can\'t connect to different domain from within an ' + 'iframe. (' + loc.href + ', ' + transUrl + ', ' + baseUrl + ')');
+          }
+          facade = new FacadeJS(new transportMap[transport](transUrl, baseUrl));
+          break;
+        case 'm':
+          facade._send(iframeMessage.data);
+          break;
+        case 'c':
+          if (facade) {
+            facade._close();
+          }
+          facade = null;
+          break;
+      }
+    };
+    eventUtils.attachEvent('message', onMessage);
+
+    // Start
+    iframeUtils.postMessage('s');
+  };
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/info-ajax.js":
+/*!*****************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/info-ajax.js ***!
+  \*****************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  objectUtils = __webpack_require__(/*! ./utils/object */ "./node_modules/sockjs-client/lib/utils/object.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:info-ajax');
+}
+function InfoAjax(url, AjaxObject) {
+  EventEmitter.call(this);
+  var self = this;
+  var t0 = +new Date();
+  this.xo = new AjaxObject('GET', url);
+  this.xo.once('finish', function (status, text) {
+    var info, rtt;
+    if (status === 200) {
+      rtt = +new Date() - t0;
+      if (text) {
+        try {
+          info = JSON.parse(text);
+        } catch (e) {
+          debug('bad json', text);
+        }
+      }
+      if (!objectUtils.isObject(info)) {
+        info = {};
+      }
+    }
+    self.emit('finish', info, rtt);
+    self.removeAllListeners();
+  });
+}
+inherits(InfoAjax, EventEmitter);
+InfoAjax.prototype.close = function () {
+  this.removeAllListeners();
+  this.xo.close();
+};
+module.exports = InfoAjax;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/info-iframe-receiver.js":
+/*!****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/info-iframe-receiver.js ***!
+  \****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  XHRLocalObject = __webpack_require__(/*! ./transport/sender/xhr-local */ "./node_modules/sockjs-client/lib/transport/sender/xhr-local.js"),
+  InfoAjax = __webpack_require__(/*! ./info-ajax */ "./node_modules/sockjs-client/lib/info-ajax.js");
+function InfoReceiverIframe(transUrl) {
+  var self = this;
+  EventEmitter.call(this);
+  this.ir = new InfoAjax(transUrl, XHRLocalObject);
+  this.ir.once('finish', function (info, rtt) {
+    self.ir = null;
+    self.emit('message', JSON.stringify([info, rtt]));
+  });
+}
+inherits(InfoReceiverIframe, EventEmitter);
+InfoReceiverIframe.transportName = 'iframe-info-receiver';
+InfoReceiverIframe.prototype.close = function () {
+  if (this.ir) {
+    this.ir.close();
+    this.ir = null;
+  }
+  this.removeAllListeners();
+};
+module.exports = InfoReceiverIframe;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/info-iframe.js":
+/*!*******************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/info-iframe.js ***!
+  \*******************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  utils = __webpack_require__(/*! ./utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  IframeTransport = __webpack_require__(/*! ./transport/iframe */ "./node_modules/sockjs-client/lib/transport/iframe.js"),
+  InfoReceiverIframe = __webpack_require__(/*! ./info-iframe-receiver */ "./node_modules/sockjs-client/lib/info-iframe-receiver.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:info-iframe');
+}
+function InfoIframe(baseUrl, url) {
+  var self = this;
+  EventEmitter.call(this);
+  var go = function go() {
+    var ifr = self.ifr = new IframeTransport(InfoReceiverIframe.transportName, url, baseUrl);
+    ifr.once('message', function (msg) {
+      if (msg) {
+        var d;
+        try {
+          d = JSON.parse(msg);
+        } catch (e) {
+          debug('bad json', msg);
+          self.emit('finish');
+          self.close();
+          return;
+        }
+        var info = d[0],
+          rtt = d[1];
+        self.emit('finish', info, rtt);
+      }
+      self.close();
+    });
+    ifr.once('close', function () {
+      self.emit('finish');
+      self.close();
+    });
+  };
+
+  // TODO this seems the same as the 'needBody' from transports
+  if (!__webpack_require__.g.document.body) {
+    utils.attachEvent('load', go);
+  } else {
+    go();
+  }
+}
+inherits(InfoIframe, EventEmitter);
+InfoIframe.enabled = function () {
+  return IframeTransport.enabled();
+};
+InfoIframe.prototype.close = function () {
+  if (this.ifr) {
+    this.ifr.close();
+  }
+  this.removeAllListeners();
+  this.ifr = null;
+};
+module.exports = InfoIframe;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/info-receiver.js":
+/*!*********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/info-receiver.js ***!
+  \*********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  urlUtils = __webpack_require__(/*! ./utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  XDR = __webpack_require__(/*! ./transport/sender/xdr */ "./node_modules/sockjs-client/lib/transport/sender/xdr.js"),
+  XHRCors = __webpack_require__(/*! ./transport/sender/xhr-cors */ "./node_modules/sockjs-client/lib/transport/sender/xhr-cors.js"),
+  XHRLocal = __webpack_require__(/*! ./transport/sender/xhr-local */ "./node_modules/sockjs-client/lib/transport/sender/xhr-local.js"),
+  XHRFake = __webpack_require__(/*! ./transport/sender/xhr-fake */ "./node_modules/sockjs-client/lib/transport/sender/xhr-fake.js"),
+  InfoIframe = __webpack_require__(/*! ./info-iframe */ "./node_modules/sockjs-client/lib/info-iframe.js"),
+  InfoAjax = __webpack_require__(/*! ./info-ajax */ "./node_modules/sockjs-client/lib/info-ajax.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:info-receiver');
+}
+function InfoReceiver(baseUrl, urlInfo) {
+  debug(baseUrl);
+  var self = this;
+  EventEmitter.call(this);
+  setTimeout(function () {
+    self.doXhr(baseUrl, urlInfo);
+  }, 0);
+}
+inherits(InfoReceiver, EventEmitter);
+
+// TODO this is currently ignoring the list of available transports and the whitelist
+
+InfoReceiver._getReceiver = function (baseUrl, url, urlInfo) {
+  // determine method of CORS support (if needed)
+  if (urlInfo.sameOrigin) {
+    return new InfoAjax(url, XHRLocal);
+  }
+  if (XHRCors.enabled) {
+    return new InfoAjax(url, XHRCors);
+  }
+  if (XDR.enabled && urlInfo.sameScheme) {
+    return new InfoAjax(url, XDR);
+  }
+  if (InfoIframe.enabled()) {
+    return new InfoIframe(baseUrl, url);
+  }
+  return new InfoAjax(url, XHRFake);
+};
+InfoReceiver.prototype.doXhr = function (baseUrl, urlInfo) {
+  var self = this,
+    url = urlUtils.addPath(baseUrl, '/info');
+  debug('doXhr', url);
+  this.xo = InfoReceiver._getReceiver(baseUrl, url, urlInfo);
+  this.timeoutRef = setTimeout(function () {
+    debug('timeout');
+    self._cleanup(false);
+    self.emit('finish');
+  }, InfoReceiver.timeout);
+  this.xo.once('finish', function (info, rtt) {
+    debug('finish', info, rtt);
+    self._cleanup(true);
+    self.emit('finish', info, rtt);
+  });
+};
+InfoReceiver.prototype._cleanup = function (wasClean) {
+  debug('_cleanup');
+  clearTimeout(this.timeoutRef);
+  this.timeoutRef = null;
+  if (!wasClean && this.xo) {
+    this.xo.close();
+  }
+  this.xo = null;
+};
+InfoReceiver.prototype.close = function () {
+  debug('close');
+  this.removeAllListeners();
+  this._cleanup(false);
+};
+InfoReceiver.timeout = 8000;
+module.exports = InfoReceiver;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/location.js":
+/*!****************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/location.js ***!
+  \****************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+module.exports = __webpack_require__.g.location || {
+  origin: 'http://localhost:80',
+  protocol: 'http:',
+  host: 'localhost',
+  port: 80,
+  href: 'http://localhost/',
+  hash: ''
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/main.js":
+/*!************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/main.js ***!
+  \************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+__webpack_require__(/*! ./shims */ "./node_modules/sockjs-client/lib/shims.js");
+var URL = __webpack_require__(/*! url-parse */ "./node_modules/url-parse/index.js"),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  random = __webpack_require__(/*! ./utils/random */ "./node_modules/sockjs-client/lib/utils/random.js"),
+  escape = __webpack_require__(/*! ./utils/escape */ "./node_modules/sockjs-client/lib/utils/escape.js"),
+  urlUtils = __webpack_require__(/*! ./utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  eventUtils = __webpack_require__(/*! ./utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  transport = __webpack_require__(/*! ./utils/transport */ "./node_modules/sockjs-client/lib/utils/transport.js"),
+  objectUtils = __webpack_require__(/*! ./utils/object */ "./node_modules/sockjs-client/lib/utils/object.js"),
+  browser = __webpack_require__(/*! ./utils/browser */ "./node_modules/sockjs-client/lib/utils/browser.js"),
+  log = __webpack_require__(/*! ./utils/log */ "./node_modules/sockjs-client/lib/utils/log.js"),
+  Event = __webpack_require__(/*! ./event/event */ "./node_modules/sockjs-client/lib/event/event.js"),
+  EventTarget = __webpack_require__(/*! ./event/eventtarget */ "./node_modules/sockjs-client/lib/event/eventtarget.js"),
+  loc = __webpack_require__(/*! ./location */ "./node_modules/sockjs-client/lib/location.js"),
+  CloseEvent = __webpack_require__(/*! ./event/close */ "./node_modules/sockjs-client/lib/event/close.js"),
+  TransportMessageEvent = __webpack_require__(/*! ./event/trans-message */ "./node_modules/sockjs-client/lib/event/trans-message.js"),
+  InfoReceiver = __webpack_require__(/*! ./info-receiver */ "./node_modules/sockjs-client/lib/info-receiver.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:main');
+}
+var transports;
+
+// follow constructor steps defined at http://dev.w3.org/html5/websockets/#the-websocket-interface
+function SockJS(url, protocols, options) {
+  if (!(this instanceof SockJS)) {
+    return new SockJS(url, protocols, options);
+  }
+  if (arguments.length < 1) {
+    throw new TypeError("Failed to construct 'SockJS: 1 argument required, but only 0 present");
+  }
+  EventTarget.call(this);
+  this.readyState = SockJS.CONNECTING;
+  this.extensions = '';
+  this.protocol = '';
+
+  // non-standard extension
+  options = options || {};
+  if (options.protocols_whitelist) {
+    log.warn("'protocols_whitelist' is DEPRECATED. Use 'transports' instead.");
+  }
+  this._transportsWhitelist = options.transports;
+  this._transportOptions = options.transportOptions || {};
+  this._timeout = options.timeout || 0;
+  var sessionId = options.sessionId || 8;
+  if (typeof sessionId === 'function') {
+    this._generateSessionId = sessionId;
+  } else if (typeof sessionId === 'number') {
+    this._generateSessionId = function () {
+      return random.string(sessionId);
+    };
+  } else {
+    throw new TypeError('If sessionId is used in the options, it needs to be a number or a function.');
+  }
+  this._server = options.server || random.numberString(1000);
+
+  // Step 1 of WS spec - parse and validate the url. Issue #8
+  var parsedUrl = new URL(url);
+  if (!parsedUrl.host || !parsedUrl.protocol) {
+    throw new SyntaxError("The URL '" + url + "' is invalid");
+  } else if (parsedUrl.hash) {
+    throw new SyntaxError('The URL must not contain a fragment');
+  } else if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
+    throw new SyntaxError("The URL's scheme must be either 'http:' or 'https:'. '" + parsedUrl.protocol + "' is not allowed.");
+  }
+  var secure = parsedUrl.protocol === 'https:';
+  // Step 2 - don't allow secure origin with an insecure protocol
+  if (loc.protocol === 'https:' && !secure) {
+    // exception is 127.0.0.0/8 and ::1 urls
+    if (!urlUtils.isLoopbackAddr(parsedUrl.hostname)) {
+      throw new Error('SecurityError: An insecure SockJS connection may not be initiated from a page loaded over HTTPS');
+    }
+  }
+
+  // Step 3 - check port access - no need here
+  // Step 4 - parse protocols argument
+  if (!protocols) {
+    protocols = [];
+  } else if (!Array.isArray(protocols)) {
+    protocols = [protocols];
+  }
+
+  // Step 5 - check protocols argument
+  var sortedProtocols = protocols.sort();
+  sortedProtocols.forEach(function (proto, i) {
+    if (!proto) {
+      throw new SyntaxError("The protocols entry '" + proto + "' is invalid.");
+    }
+    if (i < sortedProtocols.length - 1 && proto === sortedProtocols[i + 1]) {
+      throw new SyntaxError("The protocols entry '" + proto + "' is duplicated.");
+    }
+  });
+
+  // Step 6 - convert origin
+  var o = urlUtils.getOrigin(loc.href);
+  this._origin = o ? o.toLowerCase() : null;
+
+  // remove the trailing slash
+  parsedUrl.set('pathname', parsedUrl.pathname.replace(/\/+$/, ''));
+
+  // store the sanitized url
+  this.url = parsedUrl.href;
+  debug('using url', this.url);
+
+  // Step 7 - start connection in background
+  // obtain server info
+  // http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26
+  this._urlInfo = {
+    nullOrigin: !browser.hasDomain(),
+    sameOrigin: urlUtils.isOriginEqual(this.url, loc.href),
+    sameScheme: urlUtils.isSchemeEqual(this.url, loc.href)
+  };
+  this._ir = new InfoReceiver(this.url, this._urlInfo);
+  this._ir.once('finish', this._receiveInfo.bind(this));
+}
+inherits(SockJS, EventTarget);
+function userSetCode(code) {
+  return code === 1000 || code >= 3000 && code <= 4999;
+}
+SockJS.prototype.close = function (code, reason) {
+  // Step 1
+  if (code && !userSetCode(code)) {
+    throw new Error('InvalidAccessError: Invalid code');
+  }
+  // Step 2.4 states the max is 123 bytes, but we are just checking length
+  if (reason && reason.length > 123) {
+    throw new SyntaxError('reason argument has an invalid length');
+  }
+
+  // Step 3.1
+  if (this.readyState === SockJS.CLOSING || this.readyState === SockJS.CLOSED) {
+    return;
+  }
+
+  // TODO look at docs to determine how to set this
+  var wasClean = true;
+  this._close(code || 1000, reason || 'Normal closure', wasClean);
+};
+SockJS.prototype.send = function (data) {
+  // #13 - convert anything non-string to string
+  // TODO this currently turns objects into [object Object]
+  if (typeof data !== 'string') {
+    data = '' + data;
+  }
+  if (this.readyState === SockJS.CONNECTING) {
+    throw new Error('InvalidStateError: The connection has not been established yet');
+  }
+  if (this.readyState !== SockJS.OPEN) {
+    return;
+  }
+  this._transport.send(escape.quote(data));
+};
+SockJS.version = __webpack_require__(/*! ./version */ "./node_modules/sockjs-client/lib/version.js");
+SockJS.CONNECTING = 0;
+SockJS.OPEN = 1;
+SockJS.CLOSING = 2;
+SockJS.CLOSED = 3;
+SockJS.prototype._receiveInfo = function (info, rtt) {
+  debug('_receiveInfo', rtt);
+  this._ir = null;
+  if (!info) {
+    this._close(1002, 'Cannot connect to server');
+    return;
+  }
+
+  // establish a round-trip timeout (RTO) based on the
+  // round-trip time (RTT)
+  this._rto = this.countRTO(rtt);
+  // allow server to override url used for the actual transport
+  this._transUrl = info.base_url ? info.base_url : this.url;
+  info = objectUtils.extend(info, this._urlInfo);
+  debug('info', info);
+  // determine list of desired and supported transports
+  var enabledTransports = transports.filterToEnabled(this._transportsWhitelist, info);
+  this._transports = enabledTransports.main;
+  debug(this._transports.length + ' enabled transports');
+  this._connect();
+};
+SockJS.prototype._connect = function () {
+  for (var Transport = this._transports.shift(); Transport; Transport = this._transports.shift()) {
+    debug('attempt', Transport.transportName);
+    if (Transport.needBody) {
+      if (!__webpack_require__.g.document.body || typeof __webpack_require__.g.document.readyState !== 'undefined' && __webpack_require__.g.document.readyState !== 'complete' && __webpack_require__.g.document.readyState !== 'interactive') {
+        debug('waiting for body');
+        this._transports.unshift(Transport);
+        eventUtils.attachEvent('load', this._connect.bind(this));
+        return;
+      }
+    }
+
+    // calculate timeout based on RTO and round trips. Default to 5s
+    var timeoutMs = Math.max(this._timeout, this._rto * Transport.roundTrips || 5000);
+    this._transportTimeoutId = setTimeout(this._transportTimeout.bind(this), timeoutMs);
+    debug('using timeout', timeoutMs);
+    var transportUrl = urlUtils.addPath(this._transUrl, '/' + this._server + '/' + this._generateSessionId());
+    var options = this._transportOptions[Transport.transportName];
+    debug('transport url', transportUrl);
+    var transportObj = new Transport(transportUrl, this._transUrl, options);
+    transportObj.on('message', this._transportMessage.bind(this));
+    transportObj.once('close', this._transportClose.bind(this));
+    transportObj.transportName = Transport.transportName;
+    this._transport = transportObj;
+    return;
+  }
+  this._close(2000, 'All transports failed', false);
+};
+SockJS.prototype._transportTimeout = function () {
+  debug('_transportTimeout');
+  if (this.readyState === SockJS.CONNECTING) {
+    if (this._transport) {
+      this._transport.close();
+    }
+    this._transportClose(2007, 'Transport timed out');
+  }
+};
+SockJS.prototype._transportMessage = function (msg) {
+  debug('_transportMessage', msg);
+  var self = this,
+    type = msg.slice(0, 1),
+    content = msg.slice(1),
+    payload;
+
+  // first check for messages that don't need a payload
+  switch (type) {
+    case 'o':
+      this._open();
+      return;
+    case 'h':
+      this.dispatchEvent(new Event('heartbeat'));
+      debug('heartbeat', this.transport);
+      return;
+  }
+  if (content) {
+    try {
+      payload = JSON.parse(content);
+    } catch (e) {
+      debug('bad json', content);
+    }
+  }
+  if (typeof payload === 'undefined') {
+    debug('empty payload', content);
+    return;
+  }
+  switch (type) {
+    case 'a':
+      if (Array.isArray(payload)) {
+        payload.forEach(function (p) {
+          debug('message', self.transport, p);
+          self.dispatchEvent(new TransportMessageEvent(p));
+        });
+      }
+      break;
+    case 'm':
+      debug('message', this.transport, payload);
+      this.dispatchEvent(new TransportMessageEvent(payload));
+      break;
+    case 'c':
+      if (Array.isArray(payload) && payload.length === 2) {
+        this._close(payload[0], payload[1], true);
+      }
+      break;
+  }
+};
+SockJS.prototype._transportClose = function (code, reason) {
+  debug('_transportClose', this.transport, code, reason);
+  if (this._transport) {
+    this._transport.removeAllListeners();
+    this._transport = null;
+    this.transport = null;
+  }
+  if (!userSetCode(code) && code !== 2000 && this.readyState === SockJS.CONNECTING) {
+    this._connect();
+    return;
+  }
+  this._close(code, reason);
+};
+SockJS.prototype._open = function () {
+  debug('_open', this._transport && this._transport.transportName, this.readyState);
+  if (this.readyState === SockJS.CONNECTING) {
+    if (this._transportTimeoutId) {
+      clearTimeout(this._transportTimeoutId);
+      this._transportTimeoutId = null;
+    }
+    this.readyState = SockJS.OPEN;
+    this.transport = this._transport.transportName;
+    this.dispatchEvent(new Event('open'));
+    debug('connected', this.transport);
+  } else {
+    // The server might have been restarted, and lost track of our
+    // connection.
+    this._close(1006, 'Server lost session');
+  }
+};
+SockJS.prototype._close = function (code, reason, wasClean) {
+  debug('_close', this.transport, code, reason, wasClean, this.readyState);
+  var forceFail = false;
+  if (this._ir) {
+    forceFail = true;
+    this._ir.close();
+    this._ir = null;
+  }
+  if (this._transport) {
+    this._transport.close();
+    this._transport = null;
+    this.transport = null;
+  }
+  if (this.readyState === SockJS.CLOSED) {
+    throw new Error('InvalidStateError: SockJS has already been closed');
+  }
+  this.readyState = SockJS.CLOSING;
+  setTimeout(function () {
+    this.readyState = SockJS.CLOSED;
+    if (forceFail) {
+      this.dispatchEvent(new Event('error'));
+    }
+    var e = new CloseEvent('close');
+    e.wasClean = wasClean || false;
+    e.code = code || 1000;
+    e.reason = reason;
+    this.dispatchEvent(e);
+    this.onmessage = this.onclose = this.onerror = null;
+    debug('disconnected');
+  }.bind(this), 0);
+};
+
+// See: http://www.erg.abdn.ac.uk/~gerrit/dccp/notes/ccid2/rto_estimator/
+// and RFC 2988.
+SockJS.prototype.countRTO = function (rtt) {
+  // In a local environment, when using IE8/9 and the `jsonp-polling`
+  // transport the time needed to establish a connection (the time that pass
+  // from the opening of the transport to the call of `_dispatchOpen`) is
+  // around 200msec (the lower bound used in the article above) and this
+  // causes spurious timeouts. For this reason we calculate a value slightly
+  // larger than that used in the article.
+  if (rtt > 100) {
+    return 4 * rtt; // rto > 400msec
+  }
+
+  return 300 + rtt; // 300msec < rto <= 400msec
+};
+
+module.exports = function (availableTransports) {
+  transports = transport(availableTransports);
+  __webpack_require__(/*! ./iframe-bootstrap */ "./node_modules/sockjs-client/lib/iframe-bootstrap.js")(SockJS, availableTransports);
+  return SockJS;
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/shims.js":
+/*!*************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/shims.js ***!
+  \*************************************************/
+/***/ (function() {
+
+"use strict";
+/* eslint-disable */
+/* jscs: disable */
+
+
+// pulled specific shims from https://github.com/es-shims/es5-shim
+var ArrayPrototype = Array.prototype;
+var ObjectPrototype = Object.prototype;
+var FunctionPrototype = Function.prototype;
+var StringPrototype = String.prototype;
+var array_slice = ArrayPrototype.slice;
+var _toString = ObjectPrototype.toString;
+var isFunction = function isFunction(val) {
+  return ObjectPrototype.toString.call(val) === '[object Function]';
+};
+var isArray = function isArray(obj) {
+  return _toString.call(obj) === '[object Array]';
+};
+var isString = function isString(obj) {
+  return _toString.call(obj) === '[object String]';
+};
+var supportsDescriptors = Object.defineProperty && function () {
+  try {
+    Object.defineProperty({}, 'x', {});
+    return true;
+  } catch (e) {
+    /* this is ES3 */
+    return false;
+  }
+}();
+
+// Define configurable, writable and non-enumerable props
+// if they don't exist.
+var defineProperty;
+if (supportsDescriptors) {
+  defineProperty = function defineProperty(object, name, method, forceAssign) {
+    if (!forceAssign && name in object) {
+      return;
+    }
+    Object.defineProperty(object, name, {
+      configurable: true,
+      enumerable: false,
+      writable: true,
+      value: method
+    });
+  };
+} else {
+  defineProperty = function defineProperty(object, name, method, forceAssign) {
+    if (!forceAssign && name in object) {
+      return;
+    }
+    object[name] = method;
+  };
+}
+var defineProperties = function defineProperties(object, map, forceAssign) {
+  for (var name in map) {
+    if (ObjectPrototype.hasOwnProperty.call(map, name)) {
+      defineProperty(object, name, map[name], forceAssign);
+    }
+  }
+};
+var toObject = function toObject(o) {
+  if (o == null) {
+    // this matches both null and undefined
+    throw new TypeError("can't convert " + o + ' to object');
+  }
+  return Object(o);
+};
+
+//
+// Util
+// ======
+//
+
+// ES5 9.4
+// http://es5.github.com/#x9.4
+// http://jsperf.com/to-integer
+
+function toInteger(num) {
+  var n = +num;
+  if (n !== n) {
+    // isNaN
+    n = 0;
+  } else if (n !== 0 && n !== 1 / 0 && n !== -(1 / 0)) {
+    n = (n > 0 || -1) * Math.floor(Math.abs(n));
+  }
+  return n;
+}
+function ToUint32(x) {
+  return x >>> 0;
+}
+
+//
+// Function
+// ========
+//
+
+// ES-5 15.3.4.5
+// http://es5.github.com/#x15.3.4.5
+
+function Empty() {}
+defineProperties(FunctionPrototype, {
+  bind: function bind(that) {
+    // .length is 1
+    // 1. Let Target be the this value.
+    var target = this;
+    // 2. If IsCallable(Target) is false, throw a TypeError exception.
+    if (!isFunction(target)) {
+      throw new TypeError('Function.prototype.bind called on incompatible ' + target);
+    }
+    // 3. Let A be a new (possibly empty) internal list of all of the
+    //   argument values provided after thisArg (arg1, arg2 etc), in order.
+    // XXX slicedArgs will stand in for "A" if used
+    var args = array_slice.call(arguments, 1); // for normal call
+    // 4. Let F be a new native ECMAScript object.
+    // 11. Set the [[Prototype]] internal property of F to the standard
+    //   built-in Function prototype object as specified in 15.3.3.1.
+    // 12. Set the [[Call]] internal property of F as described in
+    //   15.3.4.5.1.
+    // 13. Set the [[Construct]] internal property of F as described in
+    //   15.3.4.5.2.
+    // 14. Set the [[HasInstance]] internal property of F as described in
+    //   15.3.4.5.3.
+    var binder = function binder() {
+      if (this instanceof bound) {
+        // 15.3.4.5.2 [[Construct]]
+        // When the [[Construct]] internal method of a function object,
+        // F that was created using the bind function is called with a
+        // list of arguments ExtraArgs, the following steps are taken:
+        // 1. Let target be the value of F's [[TargetFunction]]
+        //   internal property.
+        // 2. If target has no [[Construct]] internal method, a
+        //   TypeError exception is thrown.
+        // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
+        //   property.
+        // 4. Let args be a new list containing the same values as the
+        //   list boundArgs in the same order followed by the same
+        //   values as the list ExtraArgs in the same order.
+        // 5. Return the result of calling the [[Construct]] internal
+        //   method of target providing args as the arguments.
+
+        var result = target.apply(this, args.concat(array_slice.call(arguments)));
+        if (Object(result) === result) {
+          return result;
+        }
+        return this;
+      } else {
+        // 15.3.4.5.1 [[Call]]
+        // When the [[Call]] internal method of a function object, F,
+        // which was created using the bind function is called with a
+        // this value and a list of arguments ExtraArgs, the following
+        // steps are taken:
+        // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
+        //   property.
+        // 2. Let boundThis be the value of F's [[BoundThis]] internal
+        //   property.
+        // 3. Let target be the value of F's [[TargetFunction]] internal
+        //   property.
+        // 4. Let args be a new list containing the same values as the
+        //   list boundArgs in the same order followed by the same
+        //   values as the list ExtraArgs in the same order.
+        // 5. Return the result of calling the [[Call]] internal method
+        //   of target providing boundThis as the this value and
+        //   providing args as the arguments.
+
+        // equiv: target.call(this, ...boundArgs, ...args)
+        return target.apply(that, args.concat(array_slice.call(arguments)));
+      }
+    };
+
+    // 15. If the [[Class]] internal property of Target is "Function", then
+    //     a. Let L be the length property of Target minus the length of A.
+    //     b. Set the length own property of F to either 0 or L, whichever is
+    //       larger.
+    // 16. Else set the length own property of F to 0.
+
+    var boundLength = Math.max(0, target.length - args.length);
+
+    // 17. Set the attributes of the length own property of F to the values
+    //   specified in 15.3.5.1.
+    var boundArgs = [];
+    for (var i = 0; i < boundLength; i++) {
+      boundArgs.push('$' + i);
+    }
+
+    // XXX Build a dynamic function with desired amount of arguments is the only
+    // way to set the length property of a function.
+    // In environments where Content Security Policies enabled (Chrome extensions,
+    // for ex.) all use of eval or Function costructor throws an exception.
+    // However in all of these environments Function.prototype.bind exists
+    // and so this code will never be executed.
+    var bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);
+    if (target.prototype) {
+      Empty.prototype = target.prototype;
+      bound.prototype = new Empty();
+      // Clean up dangling references.
+      Empty.prototype = null;
+    }
+
+    // TODO
+    // 18. Set the [[Extensible]] internal property of F to true.
+
+    // TODO
+    // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
+    // 20. Call the [[DefineOwnProperty]] internal method of F with
+    //   arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
+    //   thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
+    //   false.
+    // 21. Call the [[DefineOwnProperty]] internal method of F with
+    //   arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
+    //   [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
+    //   and false.
+
+    // TODO
+    // NOTE Function objects created using Function.prototype.bind do not
+    // have a prototype property or the [[Code]], [[FormalParameters]], and
+    // [[Scope]] internal properties.
+    // XXX can't delete prototype in pure-js.
+
+    // 22. Return F.
+    return bound;
+  }
+});
+
+//
+// Array
+// =====
+//
+
+// ES5 15.4.3.2
+// http://es5.github.com/#x15.4.3.2
+// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
+defineProperties(Array, {
+  isArray: isArray
+});
+var boxedString = Object('a');
+var splitString = boxedString[0] !== 'a' || !(0 in boxedString);
+var properlyBoxesContext = function properlyBoxed(method) {
+  // Check node 0.6.21 bug where third parameter is not boxed
+  var properlyBoxesNonStrict = true;
+  var properlyBoxesStrict = true;
+  if (method) {
+    method.call('foo', function (_, __, context) {
+      if (typeof context !== 'object') {
+        properlyBoxesNonStrict = false;
+      }
+    });
+    method.call([1], function () {
+      'use strict';
+
+      properlyBoxesStrict = typeof this === 'string';
+    }, 'x');
+  }
+  return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
+};
+defineProperties(ArrayPrototype, {
+  forEach: function forEach(fun /*, thisp*/) {
+    var object = toObject(this),
+      self = splitString && isString(this) ? this.split('') : object,
+      thisp = arguments[1],
+      i = -1,
+      length = self.length >>> 0;
+
+    // If no callback function or if callback is not a callable function
+    if (!isFunction(fun)) {
+      throw new TypeError(); // TODO message
+    }
+
+    while (++i < length) {
+      if (i in self) {
+        // Invoke the callback function with call, passing arguments:
+        // context, property value, property key, thisArg object
+        // context
+        fun.call(thisp, self[i], i, object);
+      }
+    }
+  }
+}, !properlyBoxesContext(ArrayPrototype.forEach));
+
+// ES5 15.4.4.14
+// http://es5.github.com/#x15.4.4.14
+// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
+var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
+defineProperties(ArrayPrototype, {
+  indexOf: function indexOf(sought /*, fromIndex */) {
+    var self = splitString && isString(this) ? this.split('') : toObject(this),
+      length = self.length >>> 0;
+    if (!length) {
+      return -1;
+    }
+    var i = 0;
+    if (arguments.length > 1) {
+      i = toInteger(arguments[1]);
+    }
+
+    // handle negative indices
+    i = i >= 0 ? i : Math.max(0, length + i);
+    for (; i < length; i++) {
+      if (i in self && self[i] === sought) {
+        return i;
+      }
+    }
+    return -1;
+  }
+}, hasFirefox2IndexOfBug);
+
+//
+// String
+// ======
+//
+
+// ES5 15.5.4.14
+// http://es5.github.com/#x15.5.4.14
+
+// [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
+// Many browsers do not split properly with regular expressions or they
+// do not perform the split correctly under obscure conditions.
+// See http://blog.stevenlevithan.com/archives/cross-browser-split
+// I've tested in many browsers and this seems to cover the deviant ones:
+//    'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
+//    '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
+//    'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
+//       [undefined, "t", undefined, "e", ...]
+//    ''.split(/.?/) should be [], not [""]
+//    '.'.split(/()()/) should be ["."], not ["", "", "."]
+
+var string_split = StringPrototype.split;
+if ('ab'.split(/(?:ab)*/).length !== 2 || '.'.split(/(.?)(.?)/).length !== 4 || 'tesst'.split(/(s)*/)[1] === 't' || 'test'.split(/(?:)/, -1).length !== 4 || ''.split(/.?/).length || '.'.split(/()()/).length > 1) {
+  (function () {
+    var compliantExecNpcg = /()??/.exec('')[1] === void 0; // NPCG: nonparticipating capturing group
+
+    StringPrototype.split = function (separator, limit) {
+      var string = this;
+      if (separator === void 0 && limit === 0) {
+        return [];
+      }
+
+      // If `separator` is not a regex, use native split
+      if (_toString.call(separator) !== '[object RegExp]') {
+        return string_split.call(this, separator, limit);
+      }
+      var output = [],
+        flags = (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : '') + (separator.extended ? 'x' : '') + (
+        // Proposed for ES6
+        separator.sticky ? 'y' : ''),
+        // Firefox 3+
+        lastLastIndex = 0,
+        // Make `global` and avoid `lastIndex` issues by working with a copy
+        separator2,
+        match,
+        lastIndex,
+        lastLength;
+      separator = new RegExp(separator.source, flags + 'g');
+      string += ''; // Type-convert
+      if (!compliantExecNpcg) {
+        // Doesn't need flags gy, but they don't hurt
+        separator2 = new RegExp('^' + separator.source + '$(?!\\s)', flags);
+      }
+      /* Values for `limit`, per the spec:
+       * If undefined: 4294967295 // Math.pow(2, 32) - 1
+       * If 0, Infinity, or NaN: 0
+       * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
+       * If negative number: 4294967296 - Math.floor(Math.abs(limit))
+       * If other: Type-convert, then use the above rules
+       */
+      limit = limit === void 0 ? -1 >>> 0 :
+      // Math.pow(2, 32) - 1
+      ToUint32(limit);
+      while (match = separator.exec(string)) {
+        // `separator.lastIndex` is not reliable cross-browser
+        lastIndex = match.index + match[0].length;
+        if (lastIndex > lastLastIndex) {
+          output.push(string.slice(lastLastIndex, match.index));
+          // Fix browsers whose `exec` methods don't consistently return `undefined` for
+          // nonparticipating capturing groups
+          if (!compliantExecNpcg && match.length > 1) {
+            match[0].replace(separator2, function () {
+              for (var i = 1; i < arguments.length - 2; i++) {
+                if (arguments[i] === void 0) {
+                  match[i] = void 0;
+                }
+              }
+            });
+          }
+          if (match.length > 1 && match.index < string.length) {
+            ArrayPrototype.push.apply(output, match.slice(1));
+          }
+          lastLength = match[0].length;
+          lastLastIndex = lastIndex;
+          if (output.length >= limit) {
+            break;
+          }
+        }
+        if (separator.lastIndex === match.index) {
+          separator.lastIndex++; // Avoid an infinite loop
+        }
+      }
+
+      if (lastLastIndex === string.length) {
+        if (lastLength || !separator.test('')) {
+          output.push('');
+        }
+      } else {
+        output.push(string.slice(lastLastIndex));
+      }
+      return output.length > limit ? output.slice(0, limit) : output;
+    };
+  })();
+
+  // [bugfix, chrome]
+  // If separator is undefined, then the result array contains just one String,
+  // which is the this value (converted to a String). If limit is not undefined,
+  // then the output array is truncated so that it contains no more than limit
+  // elements.
+  // "0".split(undefined, 0) -> []
+} else if ('0'.split(void 0, 0).length) {
+  StringPrototype.split = function split(separator, limit) {
+    if (separator === void 0 && limit === 0) {
+      return [];
+    }
+    return string_split.call(this, separator, limit);
+  };
+}
+
+// ECMA-262, 3rd B.2.3
+// Not an ECMAScript standard, although ECMAScript 3rd Edition has a
+// non-normative section suggesting uniform semantics and it should be
+// normalized across all browsers
+// [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
+var string_substr = StringPrototype.substr;
+var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b';
+defineProperties(StringPrototype, {
+  substr: function substr(start, length) {
+    return string_substr.call(this, start < 0 ? (start = this.length + start) < 0 ? 0 : start : start, length);
+  }
+}, hasNegativeSubstrBug);
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport-list.js":
+/*!**********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport-list.js ***!
+  \**********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+module.exports = [
+// streaming transports
+__webpack_require__(/*! ./transport/websocket */ "./node_modules/sockjs-client/lib/transport/websocket.js"), __webpack_require__(/*! ./transport/xhr-streaming */ "./node_modules/sockjs-client/lib/transport/xhr-streaming.js"), __webpack_require__(/*! ./transport/xdr-streaming */ "./node_modules/sockjs-client/lib/transport/xdr-streaming.js"), __webpack_require__(/*! ./transport/eventsource */ "./node_modules/sockjs-client/lib/transport/eventsource.js"), __webpack_require__(/*! ./transport/lib/iframe-wrap */ "./node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js")(__webpack_require__(/*! ./transport/eventsource */ "./node_modules/sockjs-client/lib/transport/eventsource.js"))
+
+// polling transports
+, __webpack_require__(/*! ./transport/htmlfile */ "./node_modules/sockjs-client/lib/transport/htmlfile.js"), __webpack_require__(/*! ./transport/lib/iframe-wrap */ "./node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js")(__webpack_require__(/*! ./transport/htmlfile */ "./node_modules/sockjs-client/lib/transport/htmlfile.js")), __webpack_require__(/*! ./transport/xhr-polling */ "./node_modules/sockjs-client/lib/transport/xhr-polling.js"), __webpack_require__(/*! ./transport/xdr-polling */ "./node_modules/sockjs-client/lib/transport/xdr-polling.js"), __webpack_require__(/*! ./transport/lib/iframe-wrap */ "./node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js")(__webpack_require__(/*! ./transport/xhr-polling */ "./node_modules/sockjs-client/lib/transport/xhr-polling.js")), __webpack_require__(/*! ./transport/jsonp-polling */ "./node_modules/sockjs-client/lib/transport/jsonp-polling.js")];
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/browser/abstract-xhr.js":
+/*!**************************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/browser/abstract-xhr.js ***!
+  \**************************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  utils = __webpack_require__(/*! ../../utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  XHR = __webpack_require__.g.XMLHttpRequest;
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:browser:xhr');
+}
+function AbstractXHRObject(method, url, payload, opts) {
+  debug(method, url);
+  var self = this;
+  EventEmitter.call(this);
+  setTimeout(function () {
+    self._start(method, url, payload, opts);
+  }, 0);
+}
+inherits(AbstractXHRObject, EventEmitter);
+AbstractXHRObject.prototype._start = function (method, url, payload, opts) {
+  var self = this;
+  try {
+    this.xhr = new XHR();
+  } catch (x) {
+    // intentionally empty
+  }
+  if (!this.xhr) {
+    debug('no xhr');
+    this.emit('finish', 0, 'no xhr support');
+    this._cleanup();
+    return;
+  }
+
+  // several browsers cache POSTs
+  url = urlUtils.addQuery(url, 't=' + +new Date());
+
+  // Explorer tends to keep connection open, even after the
+  // tab gets closed: http://bugs.jquery.com/ticket/5280
+  this.unloadRef = utils.unloadAdd(function () {
+    debug('unload cleanup');
+    self._cleanup(true);
+  });
+  try {
+    this.xhr.open(method, url, true);
+    if (this.timeout && 'timeout' in this.xhr) {
+      this.xhr.timeout = this.timeout;
+      this.xhr.ontimeout = function () {
+        debug('xhr timeout');
+        self.emit('finish', 0, '');
+        self._cleanup(false);
+      };
+    }
+  } catch (e) {
+    debug('exception', e);
+    // IE raises an exception on wrong port.
+    this.emit('finish', 0, '');
+    this._cleanup(false);
+    return;
+  }
+  if ((!opts || !opts.noCredentials) && AbstractXHRObject.supportsCORS) {
+    debug('withCredentials');
+    // Mozilla docs says https://developer.mozilla.org/en/XMLHttpRequest :
+    // "This never affects same-site requests."
+
+    this.xhr.withCredentials = true;
+  }
+  if (opts && opts.headers) {
+    for (var key in opts.headers) {
+      this.xhr.setRequestHeader(key, opts.headers[key]);
+    }
+  }
+  this.xhr.onreadystatechange = function () {
+    if (self.xhr) {
+      var x = self.xhr;
+      var text, status;
+      debug('readyState', x.readyState);
+      switch (x.readyState) {
+        case 3:
+          // IE doesn't like peeking into responseText or status
+          // on Microsoft.XMLHTTP and readystate=3
+          try {
+            status = x.status;
+            text = x.responseText;
+          } catch (e) {
+            // intentionally empty
+          }
+          debug('status', status);
+          // IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450
+          if (status === 1223) {
+            status = 204;
+          }
+
+          // IE does return readystate == 3 for 404 answers.
+          if (status === 200 && text && text.length > 0) {
+            debug('chunk');
+            self.emit('chunk', status, text);
+          }
+          break;
+        case 4:
+          status = x.status;
+          debug('status', status);
+          // IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450
+          if (status === 1223) {
+            status = 204;
+          }
+          // IE returns this for a bad port
+          // http://msdn.microsoft.com/en-us/library/windows/desktop/aa383770(v=vs.85).aspx
+          if (status === 12005 || status === 12029) {
+            status = 0;
+          }
+          debug('finish', status, x.responseText);
+          self.emit('finish', status, x.responseText);
+          self._cleanup(false);
+          break;
+      }
+    }
+  };
+  try {
+    self.xhr.send(payload);
+  } catch (e) {
+    self.emit('finish', 0, '');
+    self._cleanup(false);
+  }
+};
+AbstractXHRObject.prototype._cleanup = function (abort) {
+  debug('cleanup');
+  if (!this.xhr) {
+    return;
+  }
+  this.removeAllListeners();
+  utils.unloadDel(this.unloadRef);
+
+  // IE needs this field to be a function
+  this.xhr.onreadystatechange = function () {};
+  if (this.xhr.ontimeout) {
+    this.xhr.ontimeout = null;
+  }
+  if (abort) {
+    try {
+      this.xhr.abort();
+    } catch (x) {
+      // intentionally empty
+    }
+  }
+  this.unloadRef = this.xhr = null;
+};
+AbstractXHRObject.prototype.close = function () {
+  debug('close');
+  this._cleanup(true);
+};
+AbstractXHRObject.enabled = !!XHR;
+// override XMLHttpRequest for IE6/7
+// obfuscate to avoid firewalls
+var axo = ['Active'].concat('Object').join('X');
+if (!AbstractXHRObject.enabled && axo in __webpack_require__.g) {
+  debug('overriding xmlhttprequest');
+  XHR = function XHR() {
+    try {
+      return new __webpack_require__.g[axo]('Microsoft.XMLHTTP');
+    } catch (e) {
+      return null;
+    }
+  };
+  AbstractXHRObject.enabled = !!new XHR();
+}
+var cors = false;
+try {
+  cors = 'withCredentials' in new XHR();
+} catch (ignored) {
+  // intentionally empty
+}
+AbstractXHRObject.supportsCORS = cors;
+module.exports = AbstractXHRObject;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/browser/eventsource.js":
+/*!*************************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/browser/eventsource.js ***!
+  \*************************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+module.exports = __webpack_require__.g.EventSource;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/browser/websocket.js":
+/*!***********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/browser/websocket.js ***!
+  \***********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var Driver = __webpack_require__.g.WebSocket || __webpack_require__.g.MozWebSocket;
+if (Driver) {
+  module.exports = function WebSocketBrowserDriver(url) {
+    return new Driver(url);
+  };
+} else {
+  module.exports = undefined;
+}
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/eventsource.js":
+/*!*****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/eventsource.js ***!
+  \*****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  AjaxBasedTransport = __webpack_require__(/*! ./lib/ajax-based */ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js"),
+  EventSourceReceiver = __webpack_require__(/*! ./receiver/eventsource */ "./node_modules/sockjs-client/lib/transport/receiver/eventsource.js"),
+  XHRCorsObject = __webpack_require__(/*! ./sender/xhr-cors */ "./node_modules/sockjs-client/lib/transport/sender/xhr-cors.js"),
+  EventSourceDriver = __webpack_require__(/*! eventsource */ "./node_modules/sockjs-client/lib/transport/browser/eventsource.js");
+function EventSourceTransport(transUrl) {
+  if (!EventSourceTransport.enabled()) {
+    throw new Error('Transport created when disabled');
+  }
+  AjaxBasedTransport.call(this, transUrl, '/eventsource', EventSourceReceiver, XHRCorsObject);
+}
+inherits(EventSourceTransport, AjaxBasedTransport);
+EventSourceTransport.enabled = function () {
+  return !!EventSourceDriver;
+};
+EventSourceTransport.transportName = 'eventsource';
+EventSourceTransport.roundTrips = 2;
+module.exports = EventSourceTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/htmlfile.js":
+/*!**************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/htmlfile.js ***!
+  \**************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  HtmlfileReceiver = __webpack_require__(/*! ./receiver/htmlfile */ "./node_modules/sockjs-client/lib/transport/receiver/htmlfile.js"),
+  XHRLocalObject = __webpack_require__(/*! ./sender/xhr-local */ "./node_modules/sockjs-client/lib/transport/sender/xhr-local.js"),
+  AjaxBasedTransport = __webpack_require__(/*! ./lib/ajax-based */ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js");
+function HtmlFileTransport(transUrl) {
+  if (!HtmlfileReceiver.enabled) {
+    throw new Error('Transport created when disabled');
+  }
+  AjaxBasedTransport.call(this, transUrl, '/htmlfile', HtmlfileReceiver, XHRLocalObject);
+}
+inherits(HtmlFileTransport, AjaxBasedTransport);
+HtmlFileTransport.enabled = function (info) {
+  return HtmlfileReceiver.enabled && info.sameOrigin;
+};
+HtmlFileTransport.transportName = 'htmlfile';
+HtmlFileTransport.roundTrips = 2;
+module.exports = HtmlFileTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/iframe.js":
+/*!************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/iframe.js ***!
+  \************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+// Few cool transports do work only for same-origin. In order to make
+// them work cross-domain we shall use iframe, served from the
+// remote domain. New browsers have capabilities to communicate with
+// cross domain iframe using postMessage(). In IE it was implemented
+// from IE 8+, but of course, IE got some details wrong:
+//    http://msdn.microsoft.com/en-us/library/cc197015(v=VS.85).aspx
+//    http://stevesouders.com/misc/test-postmessage.php
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  version = __webpack_require__(/*! ../version */ "./node_modules/sockjs-client/lib/version.js"),
+  urlUtils = __webpack_require__(/*! ../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  iframeUtils = __webpack_require__(/*! ../utils/iframe */ "./node_modules/sockjs-client/lib/utils/iframe.js"),
+  eventUtils = __webpack_require__(/*! ../utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  random = __webpack_require__(/*! ../utils/random */ "./node_modules/sockjs-client/lib/utils/random.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:transport:iframe');
+}
+function IframeTransport(transport, transUrl, baseUrl) {
+  if (!IframeTransport.enabled()) {
+    throw new Error('Transport created when disabled');
+  }
+  EventEmitter.call(this);
+  var self = this;
+  this.origin = urlUtils.getOrigin(baseUrl);
+  this.baseUrl = baseUrl;
+  this.transUrl = transUrl;
+  this.transport = transport;
+  this.windowId = random.string(8);
+  var iframeUrl = urlUtils.addPath(baseUrl, '/iframe.html') + '#' + this.windowId;
+  debug(transport, transUrl, iframeUrl);
+  this.iframeObj = iframeUtils.createIframe(iframeUrl, function (r) {
+    debug('err callback');
+    self.emit('close', 1006, 'Unable to load an iframe (' + r + ')');
+    self.close();
+  });
+  this.onmessageCallback = this._message.bind(this);
+  eventUtils.attachEvent('message', this.onmessageCallback);
+}
+inherits(IframeTransport, EventEmitter);
+IframeTransport.prototype.close = function () {
+  debug('close');
+  this.removeAllListeners();
+  if (this.iframeObj) {
+    eventUtils.detachEvent('message', this.onmessageCallback);
+    try {
+      // When the iframe is not loaded, IE raises an exception
+      // on 'contentWindow'.
+      this.postMessage('c');
+    } catch (x) {
+      // intentionally empty
+    }
+    this.iframeObj.cleanup();
+    this.iframeObj = null;
+    this.onmessageCallback = this.iframeObj = null;
+  }
+};
+IframeTransport.prototype._message = function (e) {
+  debug('message', e.data);
+  if (!urlUtils.isOriginEqual(e.origin, this.origin)) {
+    debug('not same origin', e.origin, this.origin);
+    return;
+  }
+  var iframeMessage;
+  try {
+    iframeMessage = JSON.parse(e.data);
+  } catch (ignored) {
+    debug('bad json', e.data);
+    return;
+  }
+  if (iframeMessage.windowId !== this.windowId) {
+    debug('mismatched window id', iframeMessage.windowId, this.windowId);
+    return;
+  }
+  switch (iframeMessage.type) {
+    case 's':
+      this.iframeObj.loaded();
+      // window global dependency
+      this.postMessage('s', JSON.stringify([version, this.transport, this.transUrl, this.baseUrl]));
+      break;
+    case 't':
+      this.emit('message', iframeMessage.data);
+      break;
+    case 'c':
+      var cdata;
+      try {
+        cdata = JSON.parse(iframeMessage.data);
+      } catch (ignored) {
+        debug('bad json', iframeMessage.data);
+        return;
+      }
+      this.emit('close', cdata[0], cdata[1]);
+      this.close();
+      break;
+  }
+};
+IframeTransport.prototype.postMessage = function (type, data) {
+  debug('postMessage', type, data);
+  this.iframeObj.post(JSON.stringify({
+    windowId: this.windowId,
+    type: type,
+    data: data || ''
+  }), this.origin);
+};
+IframeTransport.prototype.send = function (message) {
+  debug('send', message);
+  this.postMessage('m', message);
+};
+IframeTransport.enabled = function () {
+  return iframeUtils.iframeEnabled;
+};
+IframeTransport.transportName = 'iframe';
+IframeTransport.roundTrips = 2;
+module.exports = IframeTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/jsonp-polling.js":
+/*!*******************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/jsonp-polling.js ***!
+  \*******************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+// The simplest and most robust transport, using the well-know cross
+// domain hack - JSONP. This transport is quite inefficient - one
+// message could use up to one http request. But at least it works almost
+// everywhere.
+// Known limitations:
+//   o you will get a spinning cursor
+//   o for Konqueror a dumb timer is needed to detect errors
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  SenderReceiver = __webpack_require__(/*! ./lib/sender-receiver */ "./node_modules/sockjs-client/lib/transport/lib/sender-receiver.js"),
+  JsonpReceiver = __webpack_require__(/*! ./receiver/jsonp */ "./node_modules/sockjs-client/lib/transport/receiver/jsonp.js"),
+  jsonpSender = __webpack_require__(/*! ./sender/jsonp */ "./node_modules/sockjs-client/lib/transport/sender/jsonp.js");
+function JsonPTransport(transUrl) {
+  if (!JsonPTransport.enabled()) {
+    throw new Error('Transport created when disabled');
+  }
+  SenderReceiver.call(this, transUrl, '/jsonp', jsonpSender, JsonpReceiver);
+}
+inherits(JsonPTransport, SenderReceiver);
+JsonPTransport.enabled = function () {
+  return !!__webpack_require__.g.document;
+};
+JsonPTransport.transportName = 'jsonp-polling';
+JsonPTransport.roundTrips = 1;
+JsonPTransport.needBody = true;
+module.exports = JsonPTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js":
+/*!********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/lib/ajax-based.js ***!
+  \********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  SenderReceiver = __webpack_require__(/*! ./sender-receiver */ "./node_modules/sockjs-client/lib/transport/lib/sender-receiver.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:ajax-based');
+}
+function createAjaxSender(AjaxObject) {
+  return function (url, payload, callback) {
+    debug('create ajax sender', url, payload);
+    var opt = {};
+    if (typeof payload === 'string') {
+      opt.headers = {
+        'Content-type': 'text/plain'
+      };
+    }
+    var ajaxUrl = urlUtils.addPath(url, '/xhr_send');
+    var xo = new AjaxObject('POST', ajaxUrl, payload, opt);
+    xo.once('finish', function (status) {
+      debug('finish', status);
+      xo = null;
+      if (status !== 200 && status !== 204) {
+        return callback(new Error('http status ' + status));
+      }
+      callback();
+    });
+    return function () {
+      debug('abort');
+      xo.close();
+      xo = null;
+      var err = new Error('Aborted');
+      err.code = 1000;
+      callback(err);
+    };
+  };
+}
+function AjaxBasedTransport(transUrl, urlSuffix, Receiver, AjaxObject) {
+  SenderReceiver.call(this, transUrl, urlSuffix, createAjaxSender(AjaxObject), Receiver, AjaxObject);
+}
+inherits(AjaxBasedTransport, SenderReceiver);
+module.exports = AjaxBasedTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/lib/buffered-sender.js":
+/*!*************************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/lib/buffered-sender.js ***!
+  \*************************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter);
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:buffered-sender');
+}
+function BufferedSender(url, sender) {
+  debug(url);
+  EventEmitter.call(this);
+  this.sendBuffer = [];
+  this.sender = sender;
+  this.url = url;
+}
+inherits(BufferedSender, EventEmitter);
+BufferedSender.prototype.send = function (message) {
+  debug('send', message);
+  this.sendBuffer.push(message);
+  if (!this.sendStop) {
+    this.sendSchedule();
+  }
+};
+
+// For polling transports in a situation when in the message callback,
+// new message is being send. If the sending connection was started
+// before receiving one, it is possible to saturate the network and
+// timeout due to the lack of receiving socket. To avoid that we delay
+// sending messages by some small time, in order to let receiving
+// connection be started beforehand. This is only a halfmeasure and
+// does not fix the big problem, but it does make the tests go more
+// stable on slow networks.
+BufferedSender.prototype.sendScheduleWait = function () {
+  debug('sendScheduleWait');
+  var self = this;
+  var tref;
+  this.sendStop = function () {
+    debug('sendStop');
+    self.sendStop = null;
+    clearTimeout(tref);
+  };
+  tref = setTimeout(function () {
+    debug('timeout');
+    self.sendStop = null;
+    self.sendSchedule();
+  }, 25);
+};
+BufferedSender.prototype.sendSchedule = function () {
+  debug('sendSchedule', this.sendBuffer.length);
+  var self = this;
+  if (this.sendBuffer.length > 0) {
+    var payload = '[' + this.sendBuffer.join(',') + ']';
+    this.sendStop = this.sender(this.url, payload, function (err) {
+      self.sendStop = null;
+      if (err) {
+        debug('error', err);
+        self.emit('close', err.code || 1006, 'Sending error: ' + err);
+        self.close();
+      } else {
+        self.sendScheduleWait();
+      }
+    });
+    this.sendBuffer = [];
+  }
+};
+BufferedSender.prototype._cleanup = function () {
+  debug('_cleanup');
+  this.removeAllListeners();
+};
+BufferedSender.prototype.close = function () {
+  debug('close');
+  this._cleanup();
+  if (this.sendStop) {
+    this.sendStop();
+    this.sendStop = null;
+  }
+};
+module.exports = BufferedSender;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js":
+/*!*********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js ***!
+  \*********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  IframeTransport = __webpack_require__(/*! ../iframe */ "./node_modules/sockjs-client/lib/transport/iframe.js"),
+  objectUtils = __webpack_require__(/*! ../../utils/object */ "./node_modules/sockjs-client/lib/utils/object.js");
+module.exports = function (transport) {
+  function IframeWrapTransport(transUrl, baseUrl) {
+    IframeTransport.call(this, transport.transportName, transUrl, baseUrl);
+  }
+  inherits(IframeWrapTransport, IframeTransport);
+  IframeWrapTransport.enabled = function (url, info) {
+    if (!__webpack_require__.g.document) {
+      return false;
+    }
+    var iframeInfo = objectUtils.extend({}, info);
+    iframeInfo.sameOrigin = true;
+    return transport.enabled(iframeInfo) && IframeTransport.enabled();
+  };
+  IframeWrapTransport.transportName = 'iframe-' + transport.transportName;
+  IframeWrapTransport.needBody = true;
+  IframeWrapTransport.roundTrips = IframeTransport.roundTrips + transport.roundTrips - 1; // html, javascript (2) + transport - no CORS (1)
+
+  IframeWrapTransport.facadeTransport = transport;
+  return IframeWrapTransport;
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/lib/polling.js":
+/*!*****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/lib/polling.js ***!
+  \*****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter);
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:polling');
+}
+function Polling(Receiver, receiveUrl, AjaxObject) {
+  debug(receiveUrl);
+  EventEmitter.call(this);
+  this.Receiver = Receiver;
+  this.receiveUrl = receiveUrl;
+  this.AjaxObject = AjaxObject;
+  this._scheduleReceiver();
+}
+inherits(Polling, EventEmitter);
+Polling.prototype._scheduleReceiver = function () {
+  debug('_scheduleReceiver');
+  var self = this;
+  var poll = this.poll = new this.Receiver(this.receiveUrl, this.AjaxObject);
+  poll.on('message', function (msg) {
+    debug('message', msg);
+    self.emit('message', msg);
+  });
+  poll.once('close', function (code, reason) {
+    debug('close', code, reason, self.pollIsClosing);
+    self.poll = poll = null;
+    if (!self.pollIsClosing) {
+      if (reason === 'network') {
+        self._scheduleReceiver();
+      } else {
+        self.emit('close', code || 1006, reason);
+        self.removeAllListeners();
+      }
+    }
+  });
+};
+Polling.prototype.abort = function () {
+  debug('abort');
+  this.removeAllListeners();
+  this.pollIsClosing = true;
+  if (this.poll) {
+    this.poll.abort();
+  }
+};
+module.exports = Polling;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/lib/sender-receiver.js":
+/*!*************************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/lib/sender-receiver.js ***!
+  \*************************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  BufferedSender = __webpack_require__(/*! ./buffered-sender */ "./node_modules/sockjs-client/lib/transport/lib/buffered-sender.js"),
+  Polling = __webpack_require__(/*! ./polling */ "./node_modules/sockjs-client/lib/transport/lib/polling.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:sender-receiver');
+}
+function SenderReceiver(transUrl, urlSuffix, senderFunc, Receiver, AjaxObject) {
+  var pollUrl = urlUtils.addPath(transUrl, urlSuffix);
+  debug(pollUrl);
+  var self = this;
+  BufferedSender.call(this, transUrl, senderFunc);
+  this.poll = new Polling(Receiver, pollUrl, AjaxObject);
+  this.poll.on('message', function (msg) {
+    debug('poll message', msg);
+    self.emit('message', msg);
+  });
+  this.poll.once('close', function (code, reason) {
+    debug('poll close', code, reason);
+    self.poll = null;
+    self.emit('close', code, reason);
+    self.close();
+  });
+}
+inherits(SenderReceiver, BufferedSender);
+SenderReceiver.prototype.close = function () {
+  BufferedSender.prototype.close.call(this);
+  debug('close');
+  this.removeAllListeners();
+  if (this.poll) {
+    this.poll.abort();
+    this.poll = null;
+  }
+};
+module.exports = SenderReceiver;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/receiver/eventsource.js":
+/*!**************************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/receiver/eventsource.js ***!
+  \**************************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  EventSourceDriver = __webpack_require__(/*! eventsource */ "./node_modules/sockjs-client/lib/transport/browser/eventsource.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:receiver:eventsource');
+}
+function EventSourceReceiver(url) {
+  debug(url);
+  EventEmitter.call(this);
+  var self = this;
+  var es = this.es = new EventSourceDriver(url);
+  es.onmessage = function (e) {
+    debug('message', e.data);
+    self.emit('message', decodeURI(e.data));
+  };
+  es.onerror = function (e) {
+    debug('error', es.readyState, e);
+    // ES on reconnection has readyState = 0 or 1.
+    // on network error it's CLOSED = 2
+    var reason = es.readyState !== 2 ? 'network' : 'permanent';
+    self._cleanup();
+    self._close(reason);
+  };
+}
+inherits(EventSourceReceiver, EventEmitter);
+EventSourceReceiver.prototype.abort = function () {
+  debug('abort');
+  this._cleanup();
+  this._close('user');
+};
+EventSourceReceiver.prototype._cleanup = function () {
+  debug('cleanup');
+  var es = this.es;
+  if (es) {
+    es.onmessage = es.onerror = null;
+    es.close();
+    this.es = null;
+  }
+};
+EventSourceReceiver.prototype._close = function (reason) {
+  debug('close', reason);
+  var self = this;
+  // Safari and chrome < 15 crash if we close window before
+  // waiting for ES cleanup. See:
+  // https://code.google.com/p/chromium/issues/detail?id=89155
+  setTimeout(function () {
+    self.emit('close', null, reason);
+    self.removeAllListeners();
+  }, 200);
+};
+module.exports = EventSourceReceiver;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/receiver/htmlfile.js":
+/*!***********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/receiver/htmlfile.js ***!
+  \***********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  iframeUtils = __webpack_require__(/*! ../../utils/iframe */ "./node_modules/sockjs-client/lib/utils/iframe.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  random = __webpack_require__(/*! ../../utils/random */ "./node_modules/sockjs-client/lib/utils/random.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:receiver:htmlfile');
+}
+function HtmlfileReceiver(url) {
+  debug(url);
+  EventEmitter.call(this);
+  var self = this;
+  iframeUtils.polluteGlobalNamespace();
+  this.id = 'a' + random.string(6);
+  url = urlUtils.addQuery(url, 'c=' + decodeURIComponent(iframeUtils.WPrefix + '.' + this.id));
+  debug('using htmlfile', HtmlfileReceiver.htmlfileEnabled);
+  var constructFunc = HtmlfileReceiver.htmlfileEnabled ? iframeUtils.createHtmlfile : iframeUtils.createIframe;
+  __webpack_require__.g[iframeUtils.WPrefix][this.id] = {
+    start: function start() {
+      debug('start');
+      self.iframeObj.loaded();
+    },
+    message: function message(data) {
+      debug('message', data);
+      self.emit('message', data);
+    },
+    stop: function stop() {
+      debug('stop');
+      self._cleanup();
+      self._close('network');
+    }
+  };
+  this.iframeObj = constructFunc(url, function () {
+    debug('callback');
+    self._cleanup();
+    self._close('permanent');
+  });
+}
+inherits(HtmlfileReceiver, EventEmitter);
+HtmlfileReceiver.prototype.abort = function () {
+  debug('abort');
+  this._cleanup();
+  this._close('user');
+};
+HtmlfileReceiver.prototype._cleanup = function () {
+  debug('_cleanup');
+  if (this.iframeObj) {
+    this.iframeObj.cleanup();
+    this.iframeObj = null;
+  }
+  delete __webpack_require__.g[iframeUtils.WPrefix][this.id];
+};
+HtmlfileReceiver.prototype._close = function (reason) {
+  debug('_close', reason);
+  this.emit('close', null, reason);
+  this.removeAllListeners();
+};
+HtmlfileReceiver.htmlfileEnabled = false;
+
+// obfuscate to avoid firewalls
+var axo = ['Active'].concat('Object').join('X');
+if (axo in __webpack_require__.g) {
+  try {
+    HtmlfileReceiver.htmlfileEnabled = !!new __webpack_require__.g[axo]('htmlfile');
+  } catch (x) {
+    // intentionally empty
+  }
+}
+HtmlfileReceiver.enabled = HtmlfileReceiver.htmlfileEnabled || iframeUtils.iframeEnabled;
+module.exports = HtmlfileReceiver;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/receiver/jsonp.js":
+/*!********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/receiver/jsonp.js ***!
+  \********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var utils = __webpack_require__(/*! ../../utils/iframe */ "./node_modules/sockjs-client/lib/utils/iframe.js"),
+  random = __webpack_require__(/*! ../../utils/random */ "./node_modules/sockjs-client/lib/utils/random.js"),
+  browser = __webpack_require__(/*! ../../utils/browser */ "./node_modules/sockjs-client/lib/utils/browser.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter);
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:receiver:jsonp');
+}
+function JsonpReceiver(url) {
+  debug(url);
+  var self = this;
+  EventEmitter.call(this);
+  utils.polluteGlobalNamespace();
+  this.id = 'a' + random.string(6);
+  var urlWithId = urlUtils.addQuery(url, 'c=' + encodeURIComponent(utils.WPrefix + '.' + this.id));
+  __webpack_require__.g[utils.WPrefix][this.id] = this._callback.bind(this);
+  this._createScript(urlWithId);
+
+  // Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty.
+  this.timeoutId = setTimeout(function () {
+    debug('timeout');
+    self._abort(new Error('JSONP script loaded abnormally (timeout)'));
+  }, JsonpReceiver.timeout);
+}
+inherits(JsonpReceiver, EventEmitter);
+JsonpReceiver.prototype.abort = function () {
+  debug('abort');
+  if (__webpack_require__.g[utils.WPrefix][this.id]) {
+    var err = new Error('JSONP user aborted read');
+    err.code = 1000;
+    this._abort(err);
+  }
+};
+JsonpReceiver.timeout = 35000;
+JsonpReceiver.scriptErrorTimeout = 1000;
+JsonpReceiver.prototype._callback = function (data) {
+  debug('_callback', data);
+  this._cleanup();
+  if (this.aborting) {
+    return;
+  }
+  if (data) {
+    debug('message', data);
+    this.emit('message', data);
+  }
+  this.emit('close', null, 'network');
+  this.removeAllListeners();
+};
+JsonpReceiver.prototype._abort = function (err) {
+  debug('_abort', err);
+  this._cleanup();
+  this.aborting = true;
+  this.emit('close', err.code, err.message);
+  this.removeAllListeners();
+};
+JsonpReceiver.prototype._cleanup = function () {
+  debug('_cleanup');
+  clearTimeout(this.timeoutId);
+  if (this.script2) {
+    this.script2.parentNode.removeChild(this.script2);
+    this.script2 = null;
+  }
+  if (this.script) {
+    var script = this.script;
+    // Unfortunately, you can't really abort script loading of
+    // the script.
+    script.parentNode.removeChild(script);
+    script.onreadystatechange = script.onerror = script.onload = script.onclick = null;
+    this.script = null;
+  }
+  delete __webpack_require__.g[utils.WPrefix][this.id];
+};
+JsonpReceiver.prototype._scriptError = function () {
+  debug('_scriptError');
+  var self = this;
+  if (this.errorTimer) {
+    return;
+  }
+  this.errorTimer = setTimeout(function () {
+    if (!self.loadedOkay) {
+      self._abort(new Error('JSONP script loaded abnormally (onerror)'));
+    }
+  }, JsonpReceiver.scriptErrorTimeout);
+};
+JsonpReceiver.prototype._createScript = function (url) {
+  debug('_createScript', url);
+  var self = this;
+  var script = this.script = __webpack_require__.g.document.createElement('script');
+  var script2; // Opera synchronous load trick.
+
+  script.id = 'a' + random.string(8);
+  script.src = url;
+  script.type = 'text/javascript';
+  script.charset = 'UTF-8';
+  script.onerror = this._scriptError.bind(this);
+  script.onload = function () {
+    debug('onload');
+    self._abort(new Error('JSONP script loaded abnormally (onload)'));
+  };
+
+  // IE9 fires 'error' event after onreadystatechange or before, in random order.
+  // Use loadedOkay to determine if actually errored
+  script.onreadystatechange = function () {
+    debug('onreadystatechange', script.readyState);
+    if (/loaded|closed/.test(script.readyState)) {
+      if (script && script.htmlFor && script.onclick) {
+        self.loadedOkay = true;
+        try {
+          // In IE, actually execute the script.
+          script.onclick();
+        } catch (x) {
+          // intentionally empty
+        }
+      }
+      if (script) {
+        self._abort(new Error('JSONP script loaded abnormally (onreadystatechange)'));
+      }
+    }
+  };
+  // IE: event/htmlFor/onclick trick.
+  // One can't rely on proper order for onreadystatechange. In order to
+  // make sure, set a 'htmlFor' and 'event' properties, so that
+  // script code will be installed as 'onclick' handler for the
+  // script object. Later, onreadystatechange, manually execute this
+  // code. FF and Chrome doesn't work with 'event' and 'htmlFor'
+  // set. For reference see:
+  //   http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
+  // Also, read on that about script ordering:
+  //   http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+  if (typeof script.async === 'undefined' && __webpack_require__.g.document.attachEvent) {
+    // According to mozilla docs, in recent browsers script.async defaults
+    // to 'true', so we may use it to detect a good browser:
+    // https://developer.mozilla.org/en/HTML/Element/script
+    if (!browser.isOpera()) {
+      // Naively assume we're in IE
+      try {
+        script.htmlFor = script.id;
+        script.event = 'onclick';
+      } catch (x) {
+        // intentionally empty
+      }
+      script.async = true;
+    } else {
+      // Opera, second sync script hack
+      script2 = this.script2 = __webpack_require__.g.document.createElement('script');
+      script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};";
+      script.async = script2.async = false;
+    }
+  }
+  if (typeof script.async !== 'undefined') {
+    script.async = true;
+  }
+  var head = __webpack_require__.g.document.getElementsByTagName('head')[0];
+  head.insertBefore(script, head.firstChild);
+  if (script2) {
+    head.insertBefore(script2, head.firstChild);
+  }
+};
+module.exports = JsonpReceiver;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/receiver/xhr.js":
+/*!******************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/receiver/xhr.js ***!
+  \******************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter);
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:receiver:xhr');
+}
+function XhrReceiver(url, AjaxObject) {
+  debug(url);
+  EventEmitter.call(this);
+  var self = this;
+  this.bufferPosition = 0;
+  this.xo = new AjaxObject('POST', url, null);
+  this.xo.on('chunk', this._chunkHandler.bind(this));
+  this.xo.once('finish', function (status, text) {
+    debug('finish', status, text);
+    self._chunkHandler(status, text);
+    self.xo = null;
+    var reason = status === 200 ? 'network' : 'permanent';
+    debug('close', reason);
+    self.emit('close', null, reason);
+    self._cleanup();
+  });
+}
+inherits(XhrReceiver, EventEmitter);
+XhrReceiver.prototype._chunkHandler = function (status, text) {
+  debug('_chunkHandler', status);
+  if (status !== 200 || !text) {
+    return;
+  }
+  for (var idx = -1;; this.bufferPosition += idx + 1) {
+    var buf = text.slice(this.bufferPosition);
+    idx = buf.indexOf('\n');
+    if (idx === -1) {
+      break;
+    }
+    var msg = buf.slice(0, idx);
+    if (msg) {
+      debug('message', msg);
+      this.emit('message', msg);
+    }
+  }
+};
+XhrReceiver.prototype._cleanup = function () {
+  debug('_cleanup');
+  this.removeAllListeners();
+};
+XhrReceiver.prototype.abort = function () {
+  debug('abort');
+  if (this.xo) {
+    this.xo.close();
+    debug('close');
+    this.emit('close', null, 'user');
+    this.xo = null;
+  }
+  this._cleanup();
+};
+module.exports = XhrReceiver;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/sender/jsonp.js":
+/*!******************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/sender/jsonp.js ***!
+  \******************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var random = __webpack_require__(/*! ../../utils/random */ "./node_modules/sockjs-client/lib/utils/random.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:sender:jsonp');
+}
+var form, area;
+function createIframe(id) {
+  debug('createIframe', id);
+  try {
+    // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
+    return __webpack_require__.g.document.createElement('<iframe name="' + id + '">');
+  } catch (x) {
+    var iframe = __webpack_require__.g.document.createElement('iframe');
+    iframe.name = id;
+    return iframe;
+  }
+}
+function createForm() {
+  debug('createForm');
+  form = __webpack_require__.g.document.createElement('form');
+  form.style.display = 'none';
+  form.style.position = 'absolute';
+  form.method = 'POST';
+  form.enctype = 'application/x-www-form-urlencoded';
+  form.acceptCharset = 'UTF-8';
+  area = __webpack_require__.g.document.createElement('textarea');
+  area.name = 'd';
+  form.appendChild(area);
+  __webpack_require__.g.document.body.appendChild(form);
+}
+module.exports = function (url, payload, callback) {
+  debug(url, payload);
+  if (!form) {
+    createForm();
+  }
+  var id = 'a' + random.string(8);
+  form.target = id;
+  form.action = urlUtils.addQuery(urlUtils.addPath(url, '/jsonp_send'), 'i=' + id);
+  var iframe = createIframe(id);
+  iframe.id = id;
+  iframe.style.display = 'none';
+  form.appendChild(iframe);
+  try {
+    area.value = payload;
+  } catch (e) {
+    // seriously broken browsers get here
+  }
+  form.submit();
+  var completed = function completed(err) {
+    debug('completed', id, err);
+    if (!iframe.onerror) {
+      return;
+    }
+    iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
+    // Opera mini doesn't like if we GC iframe
+    // immediately, thus this timeout.
+    setTimeout(function () {
+      debug('cleaning up', id);
+      iframe.parentNode.removeChild(iframe);
+      iframe = null;
+    }, 500);
+    area.value = '';
+    // It is not possible to detect if the iframe succeeded or
+    // failed to submit our form.
+    callback(err);
+  };
+  iframe.onerror = function () {
+    debug('onerror', id);
+    completed();
+  };
+  iframe.onload = function () {
+    debug('onload', id);
+    completed();
+  };
+  iframe.onreadystatechange = function (e) {
+    debug('onreadystatechange', id, iframe.readyState, e);
+    if (iframe.readyState === 'complete') {
+      completed();
+    }
+  };
+  return function () {
+    debug('aborted', id);
+    completed(new Error('Aborted'));
+  };
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/sender/xdr.js":
+/*!****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/sender/xdr.js ***!
+  \****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  eventUtils = __webpack_require__(/*! ../../utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  browser = __webpack_require__(/*! ../../utils/browser */ "./node_modules/sockjs-client/lib/utils/browser.js"),
+  urlUtils = __webpack_require__(/*! ../../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:sender:xdr');
+}
+
+// References:
+//   http://ajaxian.com/archives/100-line-ajax-wrapper
+//   http://msdn.microsoft.com/en-us/library/cc288060(v=VS.85).aspx
+
+function XDRObject(method, url, payload) {
+  debug(method, url);
+  var self = this;
+  EventEmitter.call(this);
+  setTimeout(function () {
+    self._start(method, url, payload);
+  }, 0);
+}
+inherits(XDRObject, EventEmitter);
+XDRObject.prototype._start = function (method, url, payload) {
+  debug('_start');
+  var self = this;
+  var xdr = new __webpack_require__.g.XDomainRequest();
+  // IE caches even POSTs
+  url = urlUtils.addQuery(url, 't=' + +new Date());
+  xdr.onerror = function () {
+    debug('onerror');
+    self._error();
+  };
+  xdr.ontimeout = function () {
+    debug('ontimeout');
+    self._error();
+  };
+  xdr.onprogress = function () {
+    debug('progress', xdr.responseText);
+    self.emit('chunk', 200, xdr.responseText);
+  };
+  xdr.onload = function () {
+    debug('load');
+    self.emit('finish', 200, xdr.responseText);
+    self._cleanup(false);
+  };
+  this.xdr = xdr;
+  this.unloadRef = eventUtils.unloadAdd(function () {
+    self._cleanup(true);
+  });
+  try {
+    // Fails with AccessDenied if port number is bogus
+    this.xdr.open(method, url);
+    if (this.timeout) {
+      this.xdr.timeout = this.timeout;
+    }
+    this.xdr.send(payload);
+  } catch (x) {
+    this._error();
+  }
+};
+XDRObject.prototype._error = function () {
+  this.emit('finish', 0, '');
+  this._cleanup(false);
+};
+XDRObject.prototype._cleanup = function (abort) {
+  debug('cleanup', abort);
+  if (!this.xdr) {
+    return;
+  }
+  this.removeAllListeners();
+  eventUtils.unloadDel(this.unloadRef);
+  this.xdr.ontimeout = this.xdr.onerror = this.xdr.onprogress = this.xdr.onload = null;
+  if (abort) {
+    try {
+      this.xdr.abort();
+    } catch (x) {
+      // intentionally empty
+    }
+  }
+  this.unloadRef = this.xdr = null;
+};
+XDRObject.prototype.close = function () {
+  debug('close');
+  this._cleanup(true);
+};
+
+// IE 8/9 if the request target uses the same scheme - #79
+XDRObject.enabled = !!(__webpack_require__.g.XDomainRequest && browser.hasDomain());
+module.exports = XDRObject;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/sender/xhr-cors.js":
+/*!*********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/sender/xhr-cors.js ***!
+  \*********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  XhrDriver = __webpack_require__(/*! ../driver/xhr */ "./node_modules/sockjs-client/lib/transport/browser/abstract-xhr.js");
+function XHRCorsObject(method, url, payload, opts) {
+  XhrDriver.call(this, method, url, payload, opts);
+}
+inherits(XHRCorsObject, XhrDriver);
+XHRCorsObject.enabled = XhrDriver.enabled && XhrDriver.supportsCORS;
+module.exports = XHRCorsObject;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/sender/xhr-fake.js":
+/*!*********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/sender/xhr-fake.js ***!
+  \*********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js");
+function XHRFake( /* method, url, payload, opts */
+) {
+  var self = this;
+  EventEmitter.call(this);
+  this.to = setTimeout(function () {
+    self.emit('finish', 200, '{}');
+  }, XHRFake.timeout);
+}
+inherits(XHRFake, EventEmitter);
+XHRFake.prototype.close = function () {
+  clearTimeout(this.to);
+};
+XHRFake.timeout = 2000;
+module.exports = XHRFake;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/sender/xhr-local.js":
+/*!**********************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/sender/xhr-local.js ***!
+  \**********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  XhrDriver = __webpack_require__(/*! ../driver/xhr */ "./node_modules/sockjs-client/lib/transport/browser/abstract-xhr.js");
+function XHRLocalObject(method, url, payload /*, opts */) {
+  XhrDriver.call(this, method, url, payload, {
+    noCredentials: true
+  });
+}
+inherits(XHRLocalObject, XhrDriver);
+XHRLocalObject.enabled = XhrDriver.enabled;
+module.exports = XHRLocalObject;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/websocket.js":
+/*!***************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/websocket.js ***!
+  \***************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var utils = __webpack_require__(/*! ../utils/event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  urlUtils = __webpack_require__(/*! ../utils/url */ "./node_modules/sockjs-client/lib/utils/url.js"),
+  inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  EventEmitter = (__webpack_require__(/*! events */ "./node_modules/sockjs-client/lib/event/emitter.js").EventEmitter),
+  WebsocketDriver = __webpack_require__(/*! ./driver/websocket */ "./node_modules/sockjs-client/lib/transport/browser/websocket.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:websocket');
+}
+function WebSocketTransport(transUrl, ignore, options) {
+  if (!WebSocketTransport.enabled()) {
+    throw new Error('Transport created when disabled');
+  }
+  EventEmitter.call(this);
+  debug('constructor', transUrl);
+  var self = this;
+  var url = urlUtils.addPath(transUrl, '/websocket');
+  if (url.slice(0, 5) === 'https') {
+    url = 'wss' + url.slice(5);
+  } else {
+    url = 'ws' + url.slice(4);
+  }
+  this.url = url;
+  this.ws = new WebsocketDriver(this.url, [], options);
+  this.ws.onmessage = function (e) {
+    debug('message event', e.data);
+    self.emit('message', e.data);
+  };
+  // Firefox has an interesting bug. If a websocket connection is
+  // created after onunload, it stays alive even when user
+  // navigates away from the page. In such situation let's lie -
+  // let's not open the ws connection at all. See:
+  // https://github.com/sockjs/sockjs-client/issues/28
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=696085
+  this.unloadRef = utils.unloadAdd(function () {
+    debug('unload');
+    self.ws.close();
+  });
+  this.ws.onclose = function (e) {
+    debug('close event', e.code, e.reason);
+    self.emit('close', e.code, e.reason);
+    self._cleanup();
+  };
+  this.ws.onerror = function (e) {
+    debug('error event', e);
+    self.emit('close', 1006, 'WebSocket connection broken');
+    self._cleanup();
+  };
+}
+inherits(WebSocketTransport, EventEmitter);
+WebSocketTransport.prototype.send = function (data) {
+  var msg = '[' + data + ']';
+  debug('send', msg);
+  this.ws.send(msg);
+};
+WebSocketTransport.prototype.close = function () {
+  debug('close');
+  var ws = this.ws;
+  this._cleanup();
+  if (ws) {
+    ws.close();
+  }
+};
+WebSocketTransport.prototype._cleanup = function () {
+  debug('_cleanup');
+  var ws = this.ws;
+  if (ws) {
+    ws.onmessage = ws.onclose = ws.onerror = null;
+  }
+  utils.unloadDel(this.unloadRef);
+  this.unloadRef = this.ws = null;
+  this.removeAllListeners();
+};
+WebSocketTransport.enabled = function () {
+  debug('enabled');
+  return !!WebsocketDriver;
+};
+WebSocketTransport.transportName = 'websocket';
+
+// In theory, ws should require 1 round trip. But in chrome, this is
+// not very stable over SSL. Most likely a ws connection requires a
+// separate SSL connection, in which case 2 round trips are an
+// absolute minumum.
+WebSocketTransport.roundTrips = 2;
+module.exports = WebSocketTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/xdr-polling.js":
+/*!*****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/xdr-polling.js ***!
+  \*****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  AjaxBasedTransport = __webpack_require__(/*! ./lib/ajax-based */ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js"),
+  XdrStreamingTransport = __webpack_require__(/*! ./xdr-streaming */ "./node_modules/sockjs-client/lib/transport/xdr-streaming.js"),
+  XhrReceiver = __webpack_require__(/*! ./receiver/xhr */ "./node_modules/sockjs-client/lib/transport/receiver/xhr.js"),
+  XDRObject = __webpack_require__(/*! ./sender/xdr */ "./node_modules/sockjs-client/lib/transport/sender/xdr.js");
+function XdrPollingTransport(transUrl) {
+  if (!XDRObject.enabled) {
+    throw new Error('Transport created when disabled');
+  }
+  AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XDRObject);
+}
+inherits(XdrPollingTransport, AjaxBasedTransport);
+XdrPollingTransport.enabled = XdrStreamingTransport.enabled;
+XdrPollingTransport.transportName = 'xdr-polling';
+XdrPollingTransport.roundTrips = 2; // preflight, ajax
+
+module.exports = XdrPollingTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/xdr-streaming.js":
+/*!*******************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/xdr-streaming.js ***!
+  \*******************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  AjaxBasedTransport = __webpack_require__(/*! ./lib/ajax-based */ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js"),
+  XhrReceiver = __webpack_require__(/*! ./receiver/xhr */ "./node_modules/sockjs-client/lib/transport/receiver/xhr.js"),
+  XDRObject = __webpack_require__(/*! ./sender/xdr */ "./node_modules/sockjs-client/lib/transport/sender/xdr.js");
+
+// According to:
+//   http://stackoverflow.com/questions/1641507/detect-browser-support-for-cross-domain-xmlhttprequests
+//   http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
+
+function XdrStreamingTransport(transUrl) {
+  if (!XDRObject.enabled) {
+    throw new Error('Transport created when disabled');
+  }
+  AjaxBasedTransport.call(this, transUrl, '/xhr_streaming', XhrReceiver, XDRObject);
+}
+inherits(XdrStreamingTransport, AjaxBasedTransport);
+XdrStreamingTransport.enabled = function (info) {
+  if (info.cookie_needed || info.nullOrigin) {
+    return false;
+  }
+  return XDRObject.enabled && info.sameScheme;
+};
+XdrStreamingTransport.transportName = 'xdr-streaming';
+XdrStreamingTransport.roundTrips = 2; // preflight, ajax
+
+module.exports = XdrStreamingTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/xhr-polling.js":
+/*!*****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/xhr-polling.js ***!
+  \*****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  AjaxBasedTransport = __webpack_require__(/*! ./lib/ajax-based */ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js"),
+  XhrReceiver = __webpack_require__(/*! ./receiver/xhr */ "./node_modules/sockjs-client/lib/transport/receiver/xhr.js"),
+  XHRCorsObject = __webpack_require__(/*! ./sender/xhr-cors */ "./node_modules/sockjs-client/lib/transport/sender/xhr-cors.js"),
+  XHRLocalObject = __webpack_require__(/*! ./sender/xhr-local */ "./node_modules/sockjs-client/lib/transport/sender/xhr-local.js");
+function XhrPollingTransport(transUrl) {
+  if (!XHRLocalObject.enabled && !XHRCorsObject.enabled) {
+    throw new Error('Transport created when disabled');
+  }
+  AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XHRCorsObject);
+}
+inherits(XhrPollingTransport, AjaxBasedTransport);
+XhrPollingTransport.enabled = function (info) {
+  if (info.nullOrigin) {
+    return false;
+  }
+  if (XHRLocalObject.enabled && info.sameOrigin) {
+    return true;
+  }
+  return XHRCorsObject.enabled;
+};
+XhrPollingTransport.transportName = 'xhr-polling';
+XhrPollingTransport.roundTrips = 2; // preflight, ajax
+
+module.exports = XhrPollingTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/transport/xhr-streaming.js":
+/*!*******************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/transport/xhr-streaming.js ***!
+  \*******************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var inherits = __webpack_require__(/*! inherits */ "./node_modules/inherits/inherits_browser.js"),
+  AjaxBasedTransport = __webpack_require__(/*! ./lib/ajax-based */ "./node_modules/sockjs-client/lib/transport/lib/ajax-based.js"),
+  XhrReceiver = __webpack_require__(/*! ./receiver/xhr */ "./node_modules/sockjs-client/lib/transport/receiver/xhr.js"),
+  XHRCorsObject = __webpack_require__(/*! ./sender/xhr-cors */ "./node_modules/sockjs-client/lib/transport/sender/xhr-cors.js"),
+  XHRLocalObject = __webpack_require__(/*! ./sender/xhr-local */ "./node_modules/sockjs-client/lib/transport/sender/xhr-local.js"),
+  browser = __webpack_require__(/*! ../utils/browser */ "./node_modules/sockjs-client/lib/utils/browser.js");
+function XhrStreamingTransport(transUrl) {
+  if (!XHRLocalObject.enabled && !XHRCorsObject.enabled) {
+    throw new Error('Transport created when disabled');
+  }
+  AjaxBasedTransport.call(this, transUrl, '/xhr_streaming', XhrReceiver, XHRCorsObject);
+}
+inherits(XhrStreamingTransport, AjaxBasedTransport);
+XhrStreamingTransport.enabled = function (info) {
+  if (info.nullOrigin) {
+    return false;
+  }
+  // Opera doesn't support xhr-streaming #60
+  // But it might be able to #92
+  if (browser.isOpera()) {
+    return false;
+  }
+  return XHRCorsObject.enabled;
+};
+XhrStreamingTransport.transportName = 'xhr-streaming';
+XhrStreamingTransport.roundTrips = 2; // preflight, ajax
+
+// Safari gets confused when a streaming ajax request is started
+// before onload. This causes the load indicator to spin indefinetely.
+// Only require body when used in a browser
+XhrStreamingTransport.needBody = !!__webpack_require__.g.document;
+module.exports = XhrStreamingTransport;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/browser-crypto.js":
+/*!****************************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/browser-crypto.js ***!
+  \****************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+if (__webpack_require__.g.crypto && __webpack_require__.g.crypto.getRandomValues) {
+  module.exports.randomBytes = function (length) {
+    var bytes = new Uint8Array(length);
+    __webpack_require__.g.crypto.getRandomValues(bytes);
+    return bytes;
+  };
+} else {
+  module.exports.randomBytes = function (length) {
+    var bytes = new Array(length);
+    for (var i = 0; i < length; i++) {
+      bytes[i] = Math.floor(Math.random() * 256);
+    }
+    return bytes;
+  };
+}
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/browser.js":
+/*!*********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/browser.js ***!
+  \*********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+module.exports = {
+  isOpera: function isOpera() {
+    return __webpack_require__.g.navigator && /opera/i.test(__webpack_require__.g.navigator.userAgent);
+  },
+  isKonqueror: function isKonqueror() {
+    return __webpack_require__.g.navigator && /konqueror/i.test(__webpack_require__.g.navigator.userAgent);
+  }
+
+  // #187 wrap document.domain in try/catch because of WP8 from file:///
+  ,
+  hasDomain: function hasDomain() {
+    // non-browser client always has a domain
+    if (!__webpack_require__.g.document) {
+      return true;
+    }
+    try {
+      return !!__webpack_require__.g.document.domain;
+    } catch (e) {
+      return false;
+    }
+  }
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/escape.js":
+/*!********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/escape.js ***!
+  \********************************************************/
+/***/ (function(module) {
+
+"use strict";
+
+
+// Some extra characters that Chrome gets wrong, and substitutes with
+// something else on the wire.
+// eslint-disable-next-line no-control-regex, no-misleading-character-class
+var extraEscapable = /[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g,
+  extraLookup;
+
+// This may be quite slow, so let's delay until user actually uses bad
+// characters.
+var unrollLookup = function unrollLookup(escapable) {
+  var i;
+  var unrolled = {};
+  var c = [];
+  for (i = 0; i < 65536; i++) {
+    c.push(String.fromCharCode(i));
+  }
+  escapable.lastIndex = 0;
+  c.join('').replace(escapable, function (a) {
+    unrolled[a] = "\\u" + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+    return '';
+  });
+  escapable.lastIndex = 0;
+  return unrolled;
+};
+
+// Quote string, also taking care of unicode characters that browsers
+// often break. Especially, take care of unicode surrogates:
+// http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Surrogates
+module.exports = {
+  quote: function quote(string) {
+    var quoted = JSON.stringify(string);
+
+    // In most cases this should be very fast and good enough.
+    extraEscapable.lastIndex = 0;
+    if (!extraEscapable.test(quoted)) {
+      return quoted;
+    }
+    if (!extraLookup) {
+      extraLookup = unrollLookup(extraEscapable);
+    }
+    return quoted.replace(extraEscapable, function (a) {
+      return extraLookup[a];
+    });
+  }
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/event.js":
+/*!*******************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/event.js ***!
+  \*******************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var random = __webpack_require__(/*! ./random */ "./node_modules/sockjs-client/lib/utils/random.js");
+var onUnload = {},
+  afterUnload = false
+  // detect google chrome packaged apps because they don't allow the 'unload' event
+  ,
+  isChromePackagedApp = __webpack_require__.g.chrome && __webpack_require__.g.chrome.app && __webpack_require__.g.chrome.app.runtime;
+module.exports = {
+  attachEvent: function attachEvent(event, listener) {
+    if (typeof __webpack_require__.g.addEventListener !== 'undefined') {
+      __webpack_require__.g.addEventListener(event, listener, false);
+    } else if (__webpack_require__.g.document && __webpack_require__.g.attachEvent) {
+      // IE quirks.
+      // According to: http://stevesouders.com/misc/test-postmessage.php
+      // the message gets delivered only to 'document', not 'window'.
+      __webpack_require__.g.document.attachEvent('on' + event, listener);
+      // I get 'window' for ie8.
+      __webpack_require__.g.attachEvent('on' + event, listener);
+    }
+  },
+  detachEvent: function detachEvent(event, listener) {
+    if (typeof __webpack_require__.g.addEventListener !== 'undefined') {
+      __webpack_require__.g.removeEventListener(event, listener, false);
+    } else if (__webpack_require__.g.document && __webpack_require__.g.detachEvent) {
+      __webpack_require__.g.document.detachEvent('on' + event, listener);
+      __webpack_require__.g.detachEvent('on' + event, listener);
+    }
+  },
+  unloadAdd: function unloadAdd(listener) {
+    if (isChromePackagedApp) {
+      return null;
+    }
+    var ref = random.string(8);
+    onUnload[ref] = listener;
+    if (afterUnload) {
+      setTimeout(this.triggerUnloadCallbacks, 0);
+    }
+    return ref;
+  },
+  unloadDel: function unloadDel(ref) {
+    if (ref in onUnload) {
+      delete onUnload[ref];
+    }
+  },
+  triggerUnloadCallbacks: function triggerUnloadCallbacks() {
+    for (var ref in onUnload) {
+      onUnload[ref]();
+      delete onUnload[ref];
+    }
+  }
+};
+var unloadTriggered = function unloadTriggered() {
+  if (afterUnload) {
+    return;
+  }
+  afterUnload = true;
+  module.exports.triggerUnloadCallbacks();
+};
+
+// 'unload' alone is not reliable in opera within an iframe, but we
+// can't use `beforeunload` as IE fires it on javascript: links.
+if (!isChromePackagedApp) {
+  module.exports.attachEvent('unload', unloadTriggered);
+}
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/iframe.js":
+/*!********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/iframe.js ***!
+  \********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var eventUtils = __webpack_require__(/*! ./event */ "./node_modules/sockjs-client/lib/utils/event.js"),
+  browser = __webpack_require__(/*! ./browser */ "./node_modules/sockjs-client/lib/utils/browser.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:utils:iframe');
+}
+module.exports = {
+  WPrefix: '_jp',
+  currentWindowId: null,
+  polluteGlobalNamespace: function polluteGlobalNamespace() {
+    if (!(module.exports.WPrefix in __webpack_require__.g)) {
+      __webpack_require__.g[module.exports.WPrefix] = {};
+    }
+  },
+  postMessage: function postMessage(type, data) {
+    if (__webpack_require__.g.parent !== __webpack_require__.g) {
+      __webpack_require__.g.parent.postMessage(JSON.stringify({
+        windowId: module.exports.currentWindowId,
+        type: type,
+        data: data || ''
+      }), '*');
+    } else {
+      debug('Cannot postMessage, no parent window.', type, data);
+    }
+  },
+  createIframe: function createIframe(iframeUrl, errorCallback) {
+    var iframe = __webpack_require__.g.document.createElement('iframe');
+    var tref, unloadRef;
+    var unattach = function unattach() {
+      debug('unattach');
+      clearTimeout(tref);
+      // Explorer had problems with that.
+      try {
+        iframe.onload = null;
+      } catch (x) {
+        // intentionally empty
+      }
+      iframe.onerror = null;
+    };
+    var cleanup = function cleanup() {
+      debug('cleanup');
+      if (iframe) {
+        unattach();
+        // This timeout makes chrome fire onbeforeunload event
+        // within iframe. Without the timeout it goes straight to
+        // onunload.
+        setTimeout(function () {
+          if (iframe) {
+            iframe.parentNode.removeChild(iframe);
+          }
+          iframe = null;
+        }, 0);
+        eventUtils.unloadDel(unloadRef);
+      }
+    };
+    var onerror = function onerror(err) {
+      debug('onerror', err);
+      if (iframe) {
+        cleanup();
+        errorCallback(err);
+      }
+    };
+    var post = function post(msg, origin) {
+      debug('post', msg, origin);
+      setTimeout(function () {
+        try {
+          // When the iframe is not loaded, IE raises an exception
+          // on 'contentWindow'.
+          if (iframe && iframe.contentWindow) {
+            iframe.contentWindow.postMessage(msg, origin);
+          }
+        } catch (x) {
+          // intentionally empty
+        }
+      }, 0);
+    };
+    iframe.src = iframeUrl;
+    iframe.style.display = 'none';
+    iframe.style.position = 'absolute';
+    iframe.onerror = function () {
+      onerror('onerror');
+    };
+    iframe.onload = function () {
+      debug('onload');
+      // `onload` is triggered before scripts on the iframe are
+      // executed. Give it few seconds to actually load stuff.
+      clearTimeout(tref);
+      tref = setTimeout(function () {
+        onerror('onload timeout');
+      }, 2000);
+    };
+    __webpack_require__.g.document.body.appendChild(iframe);
+    tref = setTimeout(function () {
+      onerror('timeout');
+    }, 15000);
+    unloadRef = eventUtils.unloadAdd(cleanup);
+    return {
+      post: post,
+      cleanup: cleanup,
+      loaded: unattach
+    };
+  }
+
+  /* eslint no-undef: "off", new-cap: "off" */,
+  createHtmlfile: function createHtmlfile(iframeUrl, errorCallback) {
+    var axo = ['Active'].concat('Object').join('X');
+    var doc = new __webpack_require__.g[axo]('htmlfile');
+    var tref, unloadRef;
+    var iframe;
+    var unattach = function unattach() {
+      clearTimeout(tref);
+      iframe.onerror = null;
+    };
+    var cleanup = function cleanup() {
+      if (doc) {
+        unattach();
+        eventUtils.unloadDel(unloadRef);
+        iframe.parentNode.removeChild(iframe);
+        iframe = doc = null;
+        CollectGarbage();
+      }
+    };
+    var onerror = function onerror(r) {
+      debug('onerror', r);
+      if (doc) {
+        cleanup();
+        errorCallback(r);
+      }
+    };
+    var post = function post(msg, origin) {
+      try {
+        // When the iframe is not loaded, IE raises an exception
+        // on 'contentWindow'.
+        setTimeout(function () {
+          if (iframe && iframe.contentWindow) {
+            iframe.contentWindow.postMessage(msg, origin);
+          }
+        }, 0);
+      } catch (x) {
+        // intentionally empty
+      }
+    };
+    doc.open();
+    doc.write('<html><s' + 'cript>' + 'document.domain="' + __webpack_require__.g.document.domain + '";' + '</s' + 'cript></html>');
+    doc.close();
+    doc.parentWindow[module.exports.WPrefix] = __webpack_require__.g[module.exports.WPrefix];
+    var c = doc.createElement('div');
+    doc.body.appendChild(c);
+    iframe = doc.createElement('iframe');
+    c.appendChild(iframe);
+    iframe.src = iframeUrl;
+    iframe.onerror = function () {
+      onerror('onerror');
+    };
+    tref = setTimeout(function () {
+      onerror('timeout');
+    }, 15000);
+    unloadRef = eventUtils.unloadAdd(cleanup);
+    return {
+      post: post,
+      cleanup: cleanup,
+      loaded: unattach
+    };
+  }
+};
+module.exports.iframeEnabled = false;
+if (__webpack_require__.g.document) {
+  // postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with
+  // huge delay, or not at all.
+  module.exports.iframeEnabled = (typeof __webpack_require__.g.postMessage === 'function' || typeof __webpack_require__.g.postMessage === 'object') && !browser.isKonqueror();
+}
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/log.js":
+/*!*****************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/log.js ***!
+  \*****************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var logObject = {};
+['log', 'debug', 'warn'].forEach(function (level) {
+  var levelExists;
+  try {
+    levelExists = __webpack_require__.g.console && __webpack_require__.g.console[level] && __webpack_require__.g.console[level].apply;
+  } catch (e) {
+    // do nothing
+  }
+  logObject[level] = levelExists ? function () {
+    return __webpack_require__.g.console[level].apply(__webpack_require__.g.console, arguments);
+  } : level === 'log' ? function () {} : logObject.log;
+});
+module.exports = logObject;
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/object.js":
+/*!********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/object.js ***!
+  \********************************************************/
+/***/ (function(module) {
+
+"use strict";
+
+
+module.exports = {
+  isObject: function isObject(obj) {
+    var type = typeof obj;
+    return type === 'function' || type === 'object' && !!obj;
+  },
+  extend: function extend(obj) {
+    if (!this.isObject(obj)) {
+      return obj;
+    }
+    var source, prop;
+    for (var i = 1, length = arguments.length; i < length; i++) {
+      source = arguments[i];
+      for (prop in source) {
+        if (Object.prototype.hasOwnProperty.call(source, prop)) {
+          obj[prop] = source[prop];
+        }
+      }
+    }
+    return obj;
+  }
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/random.js":
+/*!********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/random.js ***!
+  \********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var crypto = __webpack_require__(/*! crypto */ "./node_modules/sockjs-client/lib/utils/browser-crypto.js");
+
+// This string has length 32, a power of 2, so the modulus doesn't introduce a
+// bias.
+var _randomStringChars = 'abcdefghijklmnopqrstuvwxyz012345';
+module.exports = {
+  string: function string(length) {
+    var max = _randomStringChars.length;
+    var bytes = crypto.randomBytes(length);
+    var ret = [];
+    for (var i = 0; i < length; i++) {
+      ret.push(_randomStringChars.substr(bytes[i] % max, 1));
+    }
+    return ret.join('');
+  },
+  number: function number(max) {
+    return Math.floor(Math.random() * max);
+  },
+  numberString: function numberString(max) {
+    var t = ('' + (max - 1)).length;
+    var p = new Array(t + 1).join('0');
+    return (p + this.number(max)).slice(-t);
+  }
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/transport.js":
+/*!***********************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/transport.js ***!
+  \***********************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:utils:transport');
+}
+module.exports = function (availableTransports) {
+  return {
+    filterToEnabled: function filterToEnabled(transportsWhitelist, info) {
+      var transports = {
+        main: [],
+        facade: []
+      };
+      if (!transportsWhitelist) {
+        transportsWhitelist = [];
+      } else if (typeof transportsWhitelist === 'string') {
+        transportsWhitelist = [transportsWhitelist];
+      }
+      availableTransports.forEach(function (trans) {
+        if (!trans) {
+          return;
+        }
+        if (trans.transportName === 'websocket' && info.websocket === false) {
+          debug('disabled from server', 'websocket');
+          return;
+        }
+        if (transportsWhitelist.length && transportsWhitelist.indexOf(trans.transportName) === -1) {
+          debug('not in whitelist', trans.transportName);
+          return;
+        }
+        if (trans.enabled(info)) {
+          debug('enabled', trans.transportName);
+          transports.main.push(trans);
+          if (trans.facadeTransport) {
+            transports.facade.push(trans.facadeTransport);
+          }
+        } else {
+          debug('disabled', trans.transportName);
+        }
+      });
+      return transports;
+    }
+  };
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/utils/url.js":
+/*!*****************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/utils/url.js ***!
+  \*****************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var URL = __webpack_require__(/*! url-parse */ "./node_modules/url-parse/index.js");
+var debug = function debug() {};
+if (true) {
+  debug = __webpack_require__(/*! debug */ "./node_modules/sockjs-client/node_modules/debug/src/browser.js")('sockjs-client:utils:url');
+}
+module.exports = {
+  getOrigin: function getOrigin(url) {
+    if (!url) {
+      return null;
+    }
+    var p = new URL(url);
+    if (p.protocol === 'file:') {
+      return null;
+    }
+    var port = p.port;
+    if (!port) {
+      port = p.protocol === 'https:' ? '443' : '80';
+    }
+    return p.protocol + '//' + p.hostname + ':' + port;
+  },
+  isOriginEqual: function isOriginEqual(a, b) {
+    var res = this.getOrigin(a) === this.getOrigin(b);
+    debug('same', a, b, res);
+    return res;
+  },
+  isSchemeEqual: function isSchemeEqual(a, b) {
+    return a.split(':')[0] === b.split(':')[0];
+  },
+  addPath: function addPath(url, path) {
+    var qs = url.split('?');
+    return qs[0] + path + (qs[1] ? '?' + qs[1] : '');
+  },
+  addQuery: function addQuery(url, q) {
+    return url + (url.indexOf('?') === -1 ? '?' + q : '&' + q);
+  },
+  isLoopbackAddr: function isLoopbackAddr(addr) {
+    return /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^\[::1\]$/.test(addr);
+  }
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/lib/version.js":
+/*!***************************************************!*\
+  !*** ./node_modules/sockjs-client/lib/version.js ***!
+  \***************************************************/
+/***/ (function(module) {
+
+module.exports = '1.6.1';
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/node_modules/debug/src/browser.js":
+/*!**********************************************************************!*\
+  !*** ./node_modules/sockjs-client/node_modules/debug/src/browser.js ***!
+  \**********************************************************************/
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+function _typeof(obj) {
+  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+    _typeof = function _typeof(obj) {
+      return typeof obj;
+    };
+  } else {
+    _typeof = function _typeof(obj) {
+      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    };
+  }
+  return _typeof(obj);
+}
+
+/* eslint-env browser */
+
+/**
+ * This is the web browser implementation of `debug()`.
+ */
+exports.log = log;
+exports.formatArgs = formatArgs;
+exports.save = save;
+exports.load = load;
+exports.useColors = useColors;
+exports.storage = localstorage();
+/**
+ * Colors.
+ */
+
+exports.colors = ['#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33'];
+/**
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
+ * and the Firebug extension (any Firefox version) are known
+ * to support "%c" CSS customizations.
+ *
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
+ */
+// eslint-disable-next-line complexity
+
+function useColors() {
+  // NB: In an Electron preload script, document will be defined but not fully
+  // initialized. Since we know we're in Chrome, we'll just detect this case
+  // explicitly
+  if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
+    return true;
+  } // Internet Explorer and Edge do not support colors.
+
+  if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
+    return false;
+  } // Is webkit? http://stackoverflow.com/a/16459606/376773
+  // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
+
+  return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance ||
+  // Is firebug? http://stackoverflow.com/a/398120/376773
+  typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) ||
+  // Is firefox >= v31?
+  // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+  typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 ||
+  // Double check webkit in userAgent just in case we are in a worker
+  typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
+}
+/**
+ * Colorize log arguments if enabled.
+ *
+ * @api public
+ */
+
+function formatArgs(args) {
+  args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff);
+  if (!this.useColors) {
+    return;
+  }
+  var c = 'color: ' + this.color;
+  args.splice(1, 0, c, 'color: inherit'); // The final "%c" is somewhat tricky, because there could be other
+  // arguments passed either before or after the %c, so we need to
+  // figure out the correct index to insert the CSS into
+
+  var index = 0;
+  var lastC = 0;
+  args[0].replace(/%[a-zA-Z%]/g, function (match) {
+    if (match === '%%') {
+      return;
+    }
+    index++;
+    if (match === '%c') {
+      // We only are interested in the *last* %c
+      // (the user may have provided their own)
+      lastC = index;
+    }
+  });
+  args.splice(lastC, 0, c);
+}
+/**
+ * Invokes `console.log()` when available.
+ * No-op when `console.log` is not a "function".
+ *
+ * @api public
+ */
+
+function log() {
+  var _console;
+
+  // This hackery is required for IE8/9, where
+  // the `console.log` function doesn't have 'apply'
+  return (typeof console === "undefined" ? "undefined" : _typeof(console)) === 'object' && console.log && (_console = console).log.apply(_console, arguments);
+}
+/**
+ * Save `namespaces`.
+ *
+ * @param {String} namespaces
+ * @api private
+ */
+
+function save(namespaces) {
+  try {
+    if (namespaces) {
+      exports.storage.setItem('debug', namespaces);
+    } else {
+      exports.storage.removeItem('debug');
+    }
+  } catch (error) {// Swallow
+    // XXX (@Qix-) should we be logging these?
+  }
+}
+/**
+ * Load `namespaces`.
+ *
+ * @return {String} returns the previously persisted debug modes
+ * @api private
+ */
+
+function load() {
+  var r;
+  try {
+    r = exports.storage.getItem('debug');
+  } catch (error) {} // Swallow
+  // XXX (@Qix-) should we be logging these?
+  // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
+
+  if (!r && typeof process !== 'undefined' && 'env' in process) {
+    r = process.env.DEBUG;
+  }
+  return r;
+}
+/**
+ * Localstorage attempts to return the localstorage.
+ *
+ * This is necessary because safari throws
+ * when a user disables cookies/localstorage
+ * and you attempt to access it.
+ *
+ * @return {LocalStorage}
+ * @api private
+ */
+
+function localstorage() {
+  try {
+    // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
+    // The Browser also has localStorage in the global context.
+    return localStorage;
+  } catch (error) {// Swallow
+    // XXX (@Qix-) should we be logging these?
+  }
+}
+module.exports = __webpack_require__(/*! ./common */ "./node_modules/sockjs-client/node_modules/debug/src/common.js")(exports);
+var formatters = module.exports.formatters;
+/**
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+ */
+
+formatters.j = function (v) {
+  try {
+    return JSON.stringify(v);
+  } catch (error) {
+    return '[UnexpectedJSONParseError]: ' + error.message;
+  }
+};
+
+/***/ }),
+
+/***/ "./node_modules/sockjs-client/node_modules/debug/src/common.js":
+/*!*********************************************************************!*\
+  !*** ./node_modules/sockjs-client/node_modules/debug/src/common.js ***!
+  \*********************************************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+/**
+ * This is the common logic for both the Node.js and web browser
+ * implementations of `debug()`.
+ */
+function setup(env) {
+  createDebug.debug = createDebug;
+  createDebug.default = createDebug;
+  createDebug.coerce = coerce;
+  createDebug.disable = disable;
+  createDebug.enable = enable;
+  createDebug.enabled = enabled;
+  createDebug.humanize = __webpack_require__(/*! ms */ "./node_modules/ms/index.js");
+  Object.keys(env).forEach(function (key) {
+    createDebug[key] = env[key];
+  });
+  /**
+  * Active `debug` instances.
+  */
+
+  createDebug.instances = [];
+  /**
+  * The currently active debug mode names, and names to skip.
+  */
+
+  createDebug.names = [];
+  createDebug.skips = [];
+  /**
+  * Map of special "%n" handling functions, for the debug "format" argument.
+  *
+  * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+  */
+
+  createDebug.formatters = {};
+  /**
+  * Selects a color for a debug namespace
+  * @param {String} namespace The namespace string for the for the debug instance to be colored
+  * @return {Number|String} An ANSI color code for the given namespace
+  * @api private
+  */
+
+  function selectColor(namespace) {
+    var hash = 0;
+    for (var i = 0; i < namespace.length; i++) {
+      hash = (hash << 5) - hash + namespace.charCodeAt(i);
+      hash |= 0; // Convert to 32bit integer
+    }
+
+    return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
+  }
+  createDebug.selectColor = selectColor;
+  /**
+  * Create a debugger with the given `namespace`.
+  *
+  * @param {String} namespace
+  * @return {Function}
+  * @api public
+  */
+
+  function createDebug(namespace) {
+    var prevTime;
+    function debug() {
+      // Disabled?
+      if (!debug.enabled) {
+        return;
+      }
+      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+        args[_key] = arguments[_key];
+      }
+      var self = debug; // Set `diff` timestamp
+
+      var curr = Number(new Date());
+      var ms = curr - (prevTime || curr);
+      self.diff = ms;
+      self.prev = prevTime;
+      self.curr = curr;
+      prevTime = curr;
+      args[0] = createDebug.coerce(args[0]);
+      if (typeof args[0] !== 'string') {
+        // Anything else let's inspect with %O
+        args.unshift('%O');
+      } // Apply any `formatters` transformations
+
+      var index = 0;
+      args[0] = args[0].replace(/%([a-zA-Z%])/g, function (match, format) {
+        // If we encounter an escaped % then don't increase the array index
+        if (match === '%%') {
+          return match;
+        }
+        index++;
+        var formatter = createDebug.formatters[format];
+        if (typeof formatter === 'function') {
+          var val = args[index];
+          match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format`
+
+          args.splice(index, 1);
+          index--;
+        }
+        return match;
+      }); // Apply env-specific formatting (colors, etc.)
+
+      createDebug.formatArgs.call(self, args);
+      var logFn = self.log || createDebug.log;
+      logFn.apply(self, args);
+    }
+    debug.namespace = namespace;
+    debug.enabled = createDebug.enabled(namespace);
+    debug.useColors = createDebug.useColors();
+    debug.color = selectColor(namespace);
+    debug.destroy = destroy;
+    debug.extend = extend; // Debug.formatArgs = formatArgs;
+    // debug.rawLog = rawLog;
+    // env-specific initialization logic for debug instances
+
+    if (typeof createDebug.init === 'function') {
+      createDebug.init(debug);
+    }
+    createDebug.instances.push(debug);
+    return debug;
+  }
+  function destroy() {
+    var index = createDebug.instances.indexOf(this);
+    if (index !== -1) {
+      createDebug.instances.splice(index, 1);
+      return true;
+    }
+    return false;
+  }
+  function extend(namespace, delimiter) {
+    return createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
+  }
+  /**
+  * Enables a debug mode by namespaces. This can include modes
+  * separated by a colon and wildcards.
+  *
+  * @param {String} namespaces
+  * @api public
+  */
+
+  function enable(namespaces) {
+    createDebug.save(namespaces);
+    createDebug.names = [];
+    createDebug.skips = [];
+    var i;
+    var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
+    var len = split.length;
+    for (i = 0; i < len; i++) {
+      if (!split[i]) {
+        // ignore empty strings
+        continue;
+      }
+      namespaces = split[i].replace(/\*/g, '.*?');
+      if (namespaces[0] === '-') {
+        createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+      } else {
+        createDebug.names.push(new RegExp('^' + namespaces + '$'));
+      }
+    }
+    for (i = 0; i < createDebug.instances.length; i++) {
+      var instance = createDebug.instances[i];
+      instance.enabled = createDebug.enabled(instance.namespace);
+    }
+  }
+  /**
+  * Disable debug output.
+  *
+  * @api public
+  */
+
+  function disable() {
+    createDebug.enable('');
+  }
+  /**
+  * Returns true if the given mode name is enabled, false otherwise.
+  *
+  * @param {String} name
+  * @return {Boolean}
+  * @api public
+  */
+
+  function enabled(name) {
+    if (name[name.length - 1] === '*') {
+      return true;
+    }
+    var i;
+    var len;
+    for (i = 0, len = createDebug.skips.length; i < len; i++) {
+      if (createDebug.skips[i].test(name)) {
+        return false;
+      }
+    }
+    for (i = 0, len = createDebug.names.length; i < len; i++) {
+      if (createDebug.names[i].test(name)) {
+        return true;
+      }
+    }
+    return false;
+  }
+  /**
+  * Coerce `val`.
+  *
+  * @param {Mixed} val
+  * @return {Mixed}
+  * @api private
+  */
+
+  function coerce(val) {
+    if (val instanceof Error) {
+      return val.stack || val.message;
+    }
+    return val;
+  }
+  createDebug.enable(createDebug.load());
+  return createDebug;
+}
+module.exports = setup;
+
+/***/ }),
+
+/***/ "./node_modules/url-parse/index.js":
+/*!*****************************************!*\
+  !*** ./node_modules/url-parse/index.js ***!
+  \*****************************************/
+/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
+
+"use strict";
+
+
+var required = __webpack_require__(/*! requires-port */ "./node_modules/requires-port/index.js"),
+  qs = __webpack_require__(/*! querystringify */ "./node_modules/querystringify/index.js"),
+  controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/,
+  CRHTLF = /[\n\r\t]/g,
+  slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//,
+  port = /:\d+$/,
+  protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i,
+  windowsDriveLetter = /^[a-zA-Z]:/;
+
+/**
+ * Remove control characters and whitespace from the beginning of a string.
+ *
+ * @param {Object|String} str String to trim.
+ * @returns {String} A new string representing `str` stripped of control
+ *     characters and whitespace from its beginning.
+ * @public
+ */
+function trimLeft(str) {
+  return (str ? str : '').toString().replace(controlOrWhitespace, '');
+}
+
+/**
+ * These are the parse rules for the URL parser, it informs the parser
+ * about:
+ *
+ * 0. The char it Needs to parse, if it's a string it should be done using
+ *    indexOf, RegExp using exec and NaN means set as current value.
+ * 1. The property we should set when parsing this value.
+ * 2. Indication if it's backwards or forward parsing, when set as number it's
+ *    the value of extra chars that should be split off.
+ * 3. Inherit from location if non existing in the parser.
+ * 4. `toLowerCase` the resulting value.
+ */
+var rules = [['#', 'hash'],
+// Extract from the back.
+['?', 'query'],
+// Extract from the back.
+function sanitize(address, url) {
+  // Sanitize what is left of the address
+  return isSpecial(url.protocol) ? address.replace(/\\/g, '/') : address;
+}, ['/', 'pathname'],
+// Extract from the back.
+['@', 'auth', 1],
+// Extract from the front.
+[NaN, 'host', undefined, 1, 1],
+// Set left over value.
+[/:(\d*)$/, 'port', undefined, 1],
+// RegExp the back.
+[NaN, 'hostname', undefined, 1, 1] // Set left over.
+];
+
+/**
+ * These properties should not be copied or inherited from. This is only needed
+ * for all non blob URL's as a blob URL does not include a hash, only the
+ * origin.
+ *
+ * @type {Object}
+ * @private
+ */
+var ignore = {
+  hash: 1,
+  query: 1
+};
+
+/**
+ * The location object differs when your code is loaded through a normal page,
+ * Worker or through a worker using a blob. And with the blobble begins the
+ * trouble as the location object will contain the URL of the blob, not the
+ * location of the page where our code is loaded in. The actual origin is
+ * encoded in the `pathname` so we can thankfully generate a good "default"
+ * location from it so we can generate proper relative URL's again.
+ *
+ * @param {Object|String} loc Optional default location object.
+ * @returns {Object} lolcation object.
+ * @public
+ */
+function lolcation(loc) {
+  var globalVar;
+  if (typeof window !== 'undefined') globalVar = window;else if (typeof __webpack_require__.g !== 'undefined') globalVar = __webpack_require__.g;else if (typeof self !== 'undefined') globalVar = self;else globalVar = {};
+  var location = globalVar.location || {};
+  loc = loc || location;
+  var finaldestination = {},
+    type = typeof loc,
+    key;
+  if ('blob:' === loc.protocol) {
+    finaldestination = new Url(unescape(loc.pathname), {});
+  } else if ('string' === type) {
+    finaldestination = new Url(loc, {});
+    for (key in ignore) delete finaldestination[key];
+  } else if ('object' === type) {
+    for (key in loc) {
+      if (key in ignore) continue;
+      finaldestination[key] = loc[key];
+    }
+    if (finaldestination.slashes === undefined) {
+      finaldestination.slashes = slashes.test(loc.href);
+    }
+  }
+  return finaldestination;
+}
+
+/**
+ * Check whether a protocol scheme is special.
+ *
+ * @param {String} The protocol scheme of the URL
+ * @return {Boolean} `true` if the protocol scheme is special, else `false`
+ * @private
+ */
+function isSpecial(scheme) {
+  return scheme === 'file:' || scheme === 'ftp:' || scheme === 'http:' || scheme === 'https:' || scheme === 'ws:' || scheme === 'wss:';
+}
+
+/**
+ * @typedef ProtocolExtract
+ * @type Object
+ * @property {String} protocol Protocol matched in the URL, in lowercase.
+ * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`.
+ * @property {String} rest Rest of the URL that is not part of the protocol.
+ */
+
+/**
+ * Extract protocol information from a URL with/without double slash ("//").
+ *
+ * @param {String} address URL we want to extract from.
+ * @param {Object} location
+ * @return {ProtocolExtract} Extracted information.
+ * @private
+ */
+function extractProtocol(address, location) {
+  address = trimLeft(address);
+  address = address.replace(CRHTLF, '');
+  location = location || {};
+  var match = protocolre.exec(address);
+  var protocol = match[1] ? match[1].toLowerCase() : '';
+  var forwardSlashes = !!match[2];
+  var otherSlashes = !!match[3];
+  var slashesCount = 0;
+  var rest;
+  if (forwardSlashes) {
+    if (otherSlashes) {
+      rest = match[2] + match[3] + match[4];
+      slashesCount = match[2].length + match[3].length;
+    } else {
+      rest = match[2] + match[4];
+      slashesCount = match[2].length;
+    }
+  } else {
+    if (otherSlashes) {
+      rest = match[3] + match[4];
+      slashesCount = match[3].length;
+    } else {
+      rest = match[4];
+    }
+  }
+  if (protocol === 'file:') {
+    if (slashesCount >= 2) {
+      rest = rest.slice(2);
+    }
+  } else if (isSpecial(protocol)) {
+    rest = match[4];
+  } else if (protocol) {
+    if (forwardSlashes) {
+      rest = rest.slice(2);
+    }
+  } else if (slashesCount >= 2 && isSpecial(location.protocol)) {
+    rest = match[4];
+  }
+  return {
+    protocol: protocol,
+    slashes: forwardSlashes || isSpecial(protocol),
+    slashesCount: slashesCount,
+    rest: rest
+  };
+}
+
+/**
+ * Resolve a relative URL pathname against a base URL pathname.
+ *
+ * @param {String} relative Pathname of the relative URL.
+ * @param {String} base Pathname of the base URL.
+ * @return {String} Resolved pathname.
+ * @private
+ */
+function resolve(relative, base) {
+  if (relative === '') return base;
+  var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/')),
+    i = path.length,
+    last = path[i - 1],
+    unshift = false,
+    up = 0;
+  while (i--) {
+    if (path[i] === '.') {
+      path.splice(i, 1);
+    } else if (path[i] === '..') {
+      path.splice(i, 1);
+      up++;
+    } else if (up) {
+      if (i === 0) unshift = true;
+      path.splice(i, 1);
+      up--;
+    }
+  }
+  if (unshift) path.unshift('');
+  if (last === '.' || last === '..') path.push('');
+  return path.join('/');
+}
+
+/**
+ * The actual URL instance. Instead of returning an object we've opted-in to
+ * create an actual constructor as it's much more memory efficient and
+ * faster and it pleases my OCD.
+ *
+ * It is worth noting that we should not use `URL` as class name to prevent
+ * clashes with the global URL instance that got introduced in browsers.
+ *
+ * @constructor
+ * @param {String} address URL we want to parse.
+ * @param {Object|String} [location] Location defaults for relative paths.
+ * @param {Boolean|Function} [parser] Parser for the query string.
+ * @private
+ */
+function Url(address, location, parser) {
+  address = trimLeft(address);
+  address = address.replace(CRHTLF, '');
+  if (!(this instanceof Url)) {
+    return new Url(address, location, parser);
+  }
+  var relative,
+    extracted,
+    parse,
+    instruction,
+    index,
+    key,
+    instructions = rules.slice(),
+    type = typeof location,
+    url = this,
+    i = 0;
+
+  //
+  // The following if statements allows this module two have compatibility with
+  // 2 different API:
+  //
+  // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments
+  //    where the boolean indicates that the query string should also be parsed.
+  //
+  // 2. The `URL` interface of the browser which accepts a URL, object as
+  //    arguments. The supplied object will be used as default values / fall-back
+  //    for relative paths.
+  //
+  if ('object' !== type && 'string' !== type) {
+    parser = location;
+    location = null;
+  }
+  if (parser && 'function' !== typeof parser) parser = qs.parse;
+  location = lolcation(location);
+
+  //
+  // Extract protocol information before running the instructions.
+  //
+  extracted = extractProtocol(address || '', location);
+  relative = !extracted.protocol && !extracted.slashes;
+  url.slashes = extracted.slashes || relative && location.slashes;
+  url.protocol = extracted.protocol || location.protocol || '';
+  address = extracted.rest;
+
+  //
+  // When the authority component is absent the URL starts with a path
+  // component.
+  //
+  if (extracted.protocol === 'file:' && (extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) || !extracted.slashes && (extracted.protocol || extracted.slashesCount < 2 || !isSpecial(url.protocol))) {
+    instructions[3] = [/(.*)/, 'pathname'];
+  }
+  for (; i < instructions.length; i++) {
+    instruction = instructions[i];
+    if (typeof instruction === 'function') {
+      address = instruction(address, url);
+      continue;
+    }
+    parse = instruction[0];
+    key = instruction[1];
+    if (parse !== parse) {
+      url[key] = address;
+    } else if ('string' === typeof parse) {
+      index = parse === '@' ? address.lastIndexOf(parse) : address.indexOf(parse);
+      if (~index) {
+        if ('number' === typeof instruction[2]) {
+          url[key] = address.slice(0, index);
+          address = address.slice(index + instruction[2]);
+        } else {
+          url[key] = address.slice(index);
+          address = address.slice(0, index);
+        }
+      }
+    } else if (index = parse.exec(address)) {
+      url[key] = index[1];
+      address = address.slice(0, index.index);
+    }
+    url[key] = url[key] || (relative && instruction[3] ? location[key] || '' : '');
+
+    //
+    // Hostname, host and protocol should be lowercased so they can be used to
+    // create a proper `origin`.
+    //
+    if (instruction[4]) url[key] = url[key].toLowerCase();
+  }
+
+  //
+  // Also parse the supplied query string in to an object. If we're supplied
+  // with a custom parser as function use that instead of the default build-in
+  // parser.
+  //
+  if (parser) url.query = parser(url.query);
+
+  //
+  // If the URL is relative, resolve the pathname against the base URL.
+  //
+  if (relative && location.slashes && url.pathname.charAt(0) !== '/' && (url.pathname !== '' || location.pathname !== '')) {
+    url.pathname = resolve(url.pathname, location.pathname);
+  }
+
+  //
+  // Default to a / for pathname if none exists. This normalizes the URL
+  // to always have a /
+  //
+  if (url.pathname.charAt(0) !== '/' && isSpecial(url.protocol)) {
+    url.pathname = '/' + url.pathname;
+  }
+
+  //
+  // We should not add port numbers if they are already the default port number
+  // for a given protocol. As the host also contains the port number we're going
+  // override it with the hostname which contains no port number.
+  //
+  if (!required(url.port, url.protocol)) {
+    url.host = url.hostname;
+    url.port = '';
+  }
+
+  //
+  // Parse down the `auth` for the username and password.
+  //
+  url.username = url.password = '';
+  if (url.auth) {
+    index = url.auth.indexOf(':');
+    if (~index) {
+      url.username = url.auth.slice(0, index);
+      url.username = encodeURIComponent(decodeURIComponent(url.username));
+      url.password = url.auth.slice(index + 1);
+      url.password = encodeURIComponent(decodeURIComponent(url.password));
+    } else {
+      url.username = encodeURIComponent(decodeURIComponent(url.auth));
+    }
+    url.auth = url.password ? url.username + ':' + url.password : url.username;
+  }
+  url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host ? url.protocol + '//' + url.host : 'null';
+
+  //
+  // The href is just the compiled result.
+  //
+  url.href = url.toString();
+}
+
+/**
+ * This is convenience method for changing properties in the URL instance to
+ * insure that they all propagate correctly.
+ *
+ * @param {String} part          Property we need to adjust.
+ * @param {Mixed} value          The newly assigned value.
+ * @param {Boolean|Function} fn  When setting the query, it will be the function
+ *                               used to parse the query.
+ *                               When setting the protocol, double slash will be
+ *                               removed from the final url if it is true.
+ * @returns {URL} URL instance for chaining.
+ * @public
+ */
+function set(part, value, fn) {
+  var url = this;
+  switch (part) {
+    case 'query':
+      if ('string' === typeof value && value.length) {
+        value = (fn || qs.parse)(value);
+      }
+      url[part] = value;
+      break;
+    case 'port':
+      url[part] = value;
+      if (!required(value, url.protocol)) {
+        url.host = url.hostname;
+        url[part] = '';
+      } else if (value) {
+        url.host = url.hostname + ':' + value;
+      }
+      break;
+    case 'hostname':
+      url[part] = value;
+      if (url.port) value += ':' + url.port;
+      url.host = value;
+      break;
+    case 'host':
+      url[part] = value;
+      if (port.test(value)) {
+        value = value.split(':');
+        url.port = value.pop();
+        url.hostname = value.join(':');
+      } else {
+        url.hostname = value;
+        url.port = '';
+      }
+      break;
+    case 'protocol':
+      url.protocol = value.toLowerCase();
+      url.slashes = !fn;
+      break;
+    case 'pathname':
+    case 'hash':
+      if (value) {
+        var char = part === 'pathname' ? '/' : '#';
+        url[part] = value.charAt(0) !== char ? char + value : value;
+      } else {
+        url[part] = value;
+      }
+      break;
+    case 'username':
+    case 'password':
+      url[part] = encodeURIComponent(value);
+      break;
+    case 'auth':
+      var index = value.indexOf(':');
+      if (~index) {
+        url.username = value.slice(0, index);
+        url.username = encodeURIComponent(decodeURIComponent(url.username));
+        url.password = value.slice(index + 1);
+        url.password = encodeURIComponent(decodeURIComponent(url.password));
+      } else {
+        url.username = encodeURIComponent(decodeURIComponent(value));
+      }
+  }
+  for (var i = 0; i < rules.length; i++) {
+    var ins = rules[i];
+    if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
+  }
+  url.auth = url.password ? url.username + ':' + url.password : url.username;
+  url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host ? url.protocol + '//' + url.host : 'null';
+  url.href = url.toString();
+  return url;
+}
+
+/**
+ * Transform the properties back in to a valid and full URL string.
+ *
+ * @param {Function} stringify Optional query stringify function.
+ * @returns {String} Compiled version of the URL.
+ * @public
+ */
+function toString(stringify) {
+  if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
+  var query,
+    url = this,
+    host = url.host,
+    protocol = url.protocol;
+  if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
+  var result = protocol + (url.protocol && url.slashes || isSpecial(url.protocol) ? '//' : '');
+  if (url.username) {
+    result += url.username;
+    if (url.password) result += ':' + url.password;
+    result += '@';
+  } else if (url.password) {
+    result += ':' + url.password;
+    result += '@';
+  } else if (url.protocol !== 'file:' && isSpecial(url.protocol) && !host && url.pathname !== '/') {
+    //
+    // Add back the empty userinfo, otherwise the original invalid URL
+    // might be transformed into a valid one with `url.pathname` as host.
+    //
+    result += '@';
+  }
+
+  //
+  // Trailing colon is removed from `url.host` when it is parsed. If it still
+  // ends with a colon, then add back the trailing colon that was removed. This
+  // prevents an invalid URL from being transformed into a valid one.
+  //
+  if (host[host.length - 1] === ':' || port.test(url.hostname) && !url.port) {
+    host += ':';
+  }
+  result += host + url.pathname;
+  query = 'object' === typeof url.query ? stringify(url.query) : url.query;
+  if (query) result += '?' !== query.charAt(0) ? '?' + query : query;
+  if (url.hash) result += url.hash;
+  return result;
+}
+Url.prototype = {
+  set: set,
+  toString: toString
+};
+
+//
+// Expose the URL parser and some additional properties that might be useful for
+// others or testing.
+//
+Url.extractProtocol = extractProtocol;
+Url.location = lolcation;
+Url.trimLeft = trimLeft;
+Url.qs = qs;
+module.exports = Url;
+
+/***/ })
+
+/******/ 	});
+/************************************************************************/
+/******/ 	// The module cache
+/******/ 	var __webpack_module_cache__ = {};
+/******/ 	
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/ 		// Check if module is in cache
+/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
+/******/ 		if (cachedModule !== undefined) {
+/******/ 			return cachedModule.exports;
+/******/ 		}
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = __webpack_module_cache__[moduleId] = {
+/******/ 			// no module.id needed
+/******/ 			// no module.loaded needed
+/******/ 			exports: {}
+/******/ 		};
+/******/ 	
+/******/ 		// Execute the module function
+/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/ 	
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+/******/ 	
+/************************************************************************/
+/******/ 	/* webpack/runtime/compat get default export */
+/******/ 	!function() {
+/******/ 		// getDefaultExport function for compatibility with non-harmony modules
+/******/ 		__webpack_require__.n = function(module) {
+/******/ 			var getter = module && module.__esModule ?
+/******/ 				function() { return module['default']; } :
+/******/ 				function() { return module; };
+/******/ 			__webpack_require__.d(getter, { a: getter });
+/******/ 			return getter;
+/******/ 		};
+/******/ 	}();
+/******/ 	
+/******/ 	/* webpack/runtime/define property getters */
+/******/ 	!function() {
+/******/ 		// define getter functions for harmony exports
+/******/ 		__webpack_require__.d = function(exports, definition) {
+/******/ 			for(var key in definition) {
+/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ 				}
+/******/ 			}
+/******/ 		};
+/******/ 	}();
+/******/ 	
+/******/ 	/* webpack/runtime/global */
+/******/ 	!function() {
+/******/ 		__webpack_require__.g = (function() {
+/******/ 			if (typeof globalThis === 'object') return globalThis;
+/******/ 			try {
+/******/ 				return this || new Function('return this')();
+/******/ 			} catch (e) {
+/******/ 				if (typeof window === 'object') return window;
+/******/ 			}
+/******/ 		})();
+/******/ 	}();
+/******/ 	
+/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
+/******/ 	!function() {
+/******/ 		__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
+/******/ 	}();
+/******/ 	
+/******/ 	/* webpack/runtime/make namespace object */
+/******/ 	!function() {
+/******/ 		// define __esModule on exports
+/******/ 		__webpack_require__.r = function(exports) {
+/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ 			}
+/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
+/******/ 		};
+/******/ 	}();
+/******/ 	
+/************************************************************************/
+var __webpack_exports__ = {};
+// This entry need to be wrapped in an IIFE because it need to be in strict mode.
+!function() {
+"use strict";
+/*!***************************************************!*\
+  !*** ./client-src/modules/sockjs-client/index.js ***!
+  \***************************************************/
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */   "default": function() { return /* reexport default from dynamic */ sockjs_client__WEBPACK_IMPORTED_MODULE_0___default.a; }
+/* harmony export */ });
+/* harmony import */ var sockjs_client__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sockjs-client */ "./node_modules/sockjs-client/lib/entry.js");
+/* harmony import */ var sockjs_client__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sockjs_client__WEBPACK_IMPORTED_MODULE_0__);
+// eslint-disable-next-line import/no-extraneous-dependencies
+
+}();
+/******/ 	return __webpack_exports__;
+/******/ })()
+;
+});
Index: frontend/node_modules/webpack-dev-server/client/overlay.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/overlay.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/overlay.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,268 @@
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
+function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
+// The error overlay is inspired (and mostly copied) from Create React App (https://github.com/facebookincubator/create-react-app)
+// They, in turn, got inspired by webpack-hot-middleware (https://github.com/glenjamin/webpack-hot-middleware).
+
+import ansiHTML from "ansi-html-community";
+import { encode } from "html-entities";
+import { listenToRuntimeError, listenToUnhandledRejection, parseErrorToStacks } from "./overlay/runtime-error.js";
+import createOverlayMachine from "./overlay/state-machine.js";
+import { containerStyle, dismissButtonStyle, headerStyle, iframeStyle, msgStyles, msgTextStyle, msgTypeStyle } from "./overlay/styles.js";
+var colors = {
+  reset: ["transparent", "transparent"],
+  black: "181818",
+  red: "E36049",
+  green: "B3CB74",
+  yellow: "FFD080",
+  blue: "7CAFC2",
+  magenta: "7FACCA",
+  cyan: "C3C2EF",
+  lightgrey: "EBE7E3",
+  darkgrey: "6D7891"
+};
+ansiHTML.setColors(colors);
+
+/**
+ * @param {string} type
+ * @param {string  | { file?: string, moduleName?: string, loc?: string, message?: string; stack?: string[] }} item
+ * @returns {{ header: string, body: string }}
+ */
+function formatProblem(type, item) {
+  var header = type === "warning" ? "WARNING" : "ERROR";
+  var body = "";
+  if (typeof item === "string") {
+    body += item;
+  } else {
+    var file = item.file || "";
+    // eslint-disable-next-line no-nested-ternary
+    var moduleName = item.moduleName ? item.moduleName.indexOf("!") !== -1 ? "".concat(item.moduleName.replace(/^(\s|\S)*!/, ""), " (").concat(item.moduleName, ")") : "".concat(item.moduleName) : "";
+    var loc = item.loc;
+    header += "".concat(moduleName || file ? " in ".concat(moduleName ? "".concat(moduleName).concat(file ? " (".concat(file, ")") : "") : file).concat(loc ? " ".concat(loc) : "") : "");
+    body += item.message || "";
+  }
+  if (Array.isArray(item.stack)) {
+    item.stack.forEach(function (stack) {
+      if (typeof stack === "string") {
+        body += "\r\n".concat(stack);
+      }
+    });
+  }
+  return {
+    header: header,
+    body: body
+  };
+}
+
+/**
+ * @typedef {Object} CreateOverlayOptions
+ * @property {string | null} trustedTypesPolicyName
+ * @property {boolean | (error: Error) => void} [catchRuntimeError]
+ */
+
+/**
+ *
+ * @param {CreateOverlayOptions} options
+ */
+var createOverlay = function createOverlay(options) {
+  /** @type {HTMLIFrameElement | null | undefined} */
+  var iframeContainerElement;
+  /** @type {HTMLDivElement | null | undefined} */
+  var containerElement;
+  /** @type {HTMLDivElement | null | undefined} */
+  var headerElement;
+  /** @type {Array<(element: HTMLDivElement) => void>} */
+  var onLoadQueue = [];
+  /** @type {TrustedTypePolicy | undefined} */
+  var overlayTrustedTypesPolicy;
+
+  /**
+   *
+   * @param {HTMLElement} element
+   * @param {CSSStyleDeclaration} style
+   */
+  function applyStyle(element, style) {
+    Object.keys(style).forEach(function (prop) {
+      element.style[prop] = style[prop];
+    });
+  }
+
+  /**
+   * @param {string | null} trustedTypesPolicyName
+   */
+  function createContainer(trustedTypesPolicyName) {
+    // Enable Trusted Types if they are available in the current browser.
+    if (window.trustedTypes) {
+      overlayTrustedTypesPolicy = window.trustedTypes.createPolicy(trustedTypesPolicyName || "webpack-dev-server#overlay", {
+        createHTML: function createHTML(value) {
+          return value;
+        }
+      });
+    }
+    iframeContainerElement = document.createElement("iframe");
+    iframeContainerElement.id = "webpack-dev-server-client-overlay";
+    iframeContainerElement.src = "about:blank";
+    applyStyle(iframeContainerElement, iframeStyle);
+    iframeContainerElement.onload = function () {
+      var contentElement = /** @type {Document} */
+      /** @type {HTMLIFrameElement} */
+      iframeContainerElement.contentDocument.createElement("div");
+      containerElement = /** @type {Document} */
+      /** @type {HTMLIFrameElement} */
+      iframeContainerElement.contentDocument.createElement("div");
+      contentElement.id = "webpack-dev-server-client-overlay-div";
+      applyStyle(contentElement, containerStyle);
+      headerElement = document.createElement("div");
+      headerElement.innerText = "Compiled with problems:";
+      applyStyle(headerElement, headerStyle);
+      var closeButtonElement = document.createElement("button");
+      applyStyle(closeButtonElement, dismissButtonStyle);
+      closeButtonElement.innerText = "×";
+      closeButtonElement.ariaLabel = "Dismiss";
+      closeButtonElement.addEventListener("click", function () {
+        // eslint-disable-next-line no-use-before-define
+        overlayService.send({
+          type: "DISMISS"
+        });
+      });
+      contentElement.appendChild(headerElement);
+      contentElement.appendChild(closeButtonElement);
+      contentElement.appendChild(containerElement);
+
+      /** @type {Document} */
+      /** @type {HTMLIFrameElement} */
+      iframeContainerElement.contentDocument.body.appendChild(contentElement);
+      onLoadQueue.forEach(function (onLoad) {
+        onLoad( /** @type {HTMLDivElement} */contentElement);
+      });
+      onLoadQueue = [];
+
+      /** @type {HTMLIFrameElement} */
+      iframeContainerElement.onload = null;
+    };
+    document.body.appendChild(iframeContainerElement);
+  }
+
+  /**
+   * @param {(element: HTMLDivElement) => void} callback
+   * @param {string | null} trustedTypesPolicyName
+   */
+  function ensureOverlayExists(callback, trustedTypesPolicyName) {
+    if (containerElement) {
+      containerElement.innerHTML = "";
+      // Everything is ready, call the callback right away.
+      callback(containerElement);
+      return;
+    }
+    onLoadQueue.push(callback);
+    if (iframeContainerElement) {
+      return;
+    }
+    createContainer(trustedTypesPolicyName);
+  }
+
+  // Successful compilation.
+  function hide() {
+    if (!iframeContainerElement) {
+      return;
+    }
+
+    // Clean up and reset internal state.
+    document.body.removeChild(iframeContainerElement);
+    iframeContainerElement = null;
+    containerElement = null;
+  }
+
+  // Compilation with errors (e.g. syntax error or missing modules).
+  /**
+   * @param {string} type
+   * @param {Array<string  | { moduleIdentifier?: string, moduleName?: string, loc?: string, message?: string }>} messages
+   * @param {string | null} trustedTypesPolicyName
+   * @param {'build' | 'runtime'} messageSource
+   */
+  function show(type, messages, trustedTypesPolicyName, messageSource) {
+    ensureOverlayExists(function () {
+      headerElement.innerText = messageSource === "runtime" ? "Uncaught runtime errors:" : "Compiled with problems:";
+      messages.forEach(function (message) {
+        var entryElement = document.createElement("div");
+        var msgStyle = type === "warning" ? msgStyles.warning : msgStyles.error;
+        applyStyle(entryElement, _objectSpread(_objectSpread({}, msgStyle), {}, {
+          padding: "1rem 1rem 1.5rem 1rem"
+        }));
+        var typeElement = document.createElement("div");
+        var _formatProblem = formatProblem(type, message),
+          header = _formatProblem.header,
+          body = _formatProblem.body;
+        typeElement.innerText = header;
+        applyStyle(typeElement, msgTypeStyle);
+        if (message.moduleIdentifier) {
+          applyStyle(typeElement, {
+            cursor: "pointer"
+          });
+          // element.dataset not supported in IE
+          typeElement.setAttribute("data-can-open", true);
+          typeElement.addEventListener("click", function () {
+            fetch("/webpack-dev-server/open-editor?fileName=".concat(message.moduleIdentifier));
+          });
+        }
+
+        // Make it look similar to our terminal.
+        var text = ansiHTML(encode(body));
+        var messageTextNode = document.createElement("div");
+        applyStyle(messageTextNode, msgTextStyle);
+        messageTextNode.innerHTML = overlayTrustedTypesPolicy ? overlayTrustedTypesPolicy.createHTML(text) : text;
+        entryElement.appendChild(typeElement);
+        entryElement.appendChild(messageTextNode);
+
+        /** @type {HTMLDivElement} */
+        containerElement.appendChild(entryElement);
+      });
+    }, trustedTypesPolicyName);
+  }
+  var overlayService = createOverlayMachine({
+    showOverlay: function showOverlay(_ref) {
+      var _ref$level = _ref.level,
+        level = _ref$level === void 0 ? "error" : _ref$level,
+        messages = _ref.messages,
+        messageSource = _ref.messageSource;
+      return show(level, messages, options.trustedTypesPolicyName, messageSource);
+    },
+    hideOverlay: hide
+  });
+  if (options.catchRuntimeError) {
+    /**
+     * @param {Error | undefined} error
+     * @param {string} fallbackMessage
+     */
+    var handleError = function handleError(error, fallbackMessage) {
+      var errorObject = error instanceof Error ? error : new Error(error || fallbackMessage);
+      var shouldDisplay = typeof options.catchRuntimeError === "function" ? options.catchRuntimeError(errorObject) : true;
+      if (shouldDisplay) {
+        overlayService.send({
+          type: "RUNTIME_ERROR",
+          messages: [{
+            message: errorObject.message,
+            stack: parseErrorToStacks(errorObject)
+          }]
+        });
+      }
+    };
+    listenToRuntimeError(function (errorEvent) {
+      // error property may be empty in older browser like IE
+      var error = errorEvent.error,
+        message = errorEvent.message;
+      if (!error && !message) {
+        return;
+      }
+      handleError(error, message);
+    });
+    listenToUnhandledRejection(function (promiseRejectionEvent) {
+      var reason = promiseRejectionEvent.reason;
+      handleError(reason, "Unknown promise rejection reason");
+    });
+  }
+  return overlayService;
+};
+export { formatProblem, createOverlay };
Index: frontend/node_modules/webpack-dev-server/client/overlay/fsm.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/overlay/fsm.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/overlay/fsm.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
+function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
+/**
+ * @typedef {Object} StateDefinitions
+ * @property {{[event: string]: { target: string; actions?: Array<string> }}} [on]
+ */
+
+/**
+ * @typedef {Object} Options
+ * @property {{[state: string]: StateDefinitions}} states
+ * @property {object} context;
+ * @property {string} initial
+ */
+
+/**
+ * @typedef {Object} Implementation
+ * @property {{[actionName: string]: (ctx: object, event: any) => object}} actions
+ */
+
+/**
+ * A simplified `createMachine` from `@xstate/fsm` with the following differences:
+ *
+ *  - the returned machine is technically a "service". No `interpret(machine).start()` is needed.
+ *  - the state definition only support `on` and target must be declared with { target: 'nextState', actions: [] } explicitly.
+ *  - event passed to `send` must be an object with `type` property.
+ *  - actions implementation will be [assign action](https://xstate.js.org/docs/guides/context.html#assign-action) if you return any value.
+ *  Do not return anything if you just want to invoke side effect.
+ *
+ * The goal of this custom function is to avoid installing the entire `'xstate/fsm'` package, while enabling modeling using
+ * state machine. You can copy the first parameter into the editor at https://stately.ai/viz to visualize the state machine.
+ *
+ * @param {Options} options
+ * @param {Implementation} implementation
+ */
+function createMachine(_ref, _ref2) {
+  var states = _ref.states,
+    context = _ref.context,
+    initial = _ref.initial;
+  var actions = _ref2.actions;
+  var currentState = initial;
+  var currentContext = context;
+  return {
+    send: function send(event) {
+      var currentStateOn = states[currentState].on;
+      var transitionConfig = currentStateOn && currentStateOn[event.type];
+      if (transitionConfig) {
+        currentState = transitionConfig.target;
+        if (transitionConfig.actions) {
+          transitionConfig.actions.forEach(function (actName) {
+            var actionImpl = actions[actName];
+            var nextContextValue = actionImpl && actionImpl(currentContext, event);
+            if (nextContextValue) {
+              currentContext = _objectSpread(_objectSpread({}, currentContext), nextContextValue);
+            }
+          });
+        }
+      }
+    }
+  };
+}
+export default createMachine;
Index: frontend/node_modules/webpack-dev-server/client/overlay/runtime-error.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/overlay/runtime-error.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/overlay/runtime-error.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+/**
+ *
+ * @param {Error} error
+ */
+function parseErrorToStacks(error) {
+  if (!error || !(error instanceof Error)) {
+    throw new Error("parseErrorToStacks expects Error object");
+  }
+  if (typeof error.stack === "string") {
+    return error.stack.split("\n").filter(function (stack) {
+      return stack !== "Error: ".concat(error.message);
+    });
+  }
+}
+
+/**
+ * @callback ErrorCallback
+ * @param {ErrorEvent} error
+ * @returns {void}
+ */
+
+/**
+ * @param {ErrorCallback} callback
+ */
+function listenToRuntimeError(callback) {
+  window.addEventListener("error", callback);
+  return function cleanup() {
+    window.removeEventListener("error", callback);
+  };
+}
+
+/**
+ * @callback UnhandledRejectionCallback
+ * @param {PromiseRejectionEvent} rejectionEvent
+ * @returns {void}
+ */
+
+/**
+ * @param {UnhandledRejectionCallback} callback
+ */
+function listenToUnhandledRejection(callback) {
+  window.addEventListener("unhandledrejection", callback);
+  return function cleanup() {
+    window.removeEventListener("unhandledrejection", callback);
+  };
+}
+export { listenToRuntimeError, listenToUnhandledRejection, parseErrorToStacks };
Index: frontend/node_modules/webpack-dev-server/client/overlay/state-machine.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/overlay/state-machine.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/overlay/state-machine.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,100 @@
+import createMachine from "./fsm.js";
+
+/**
+ * @typedef {Object} ShowOverlayData
+ * @property {'warning' | 'error'} level
+ * @property {Array<string  | { moduleIdentifier?: string, moduleName?: string, loc?: string, message?: string }>} messages
+ * @property {'build' | 'runtime'} messageSource
+ */
+
+/**
+ * @typedef {Object} CreateOverlayMachineOptions
+ * @property {(data: ShowOverlayData) => void} showOverlay
+ * @property {() => void} hideOverlay
+ */
+
+/**
+ * @param {CreateOverlayMachineOptions} options
+ */
+var createOverlayMachine = function createOverlayMachine(options) {
+  var hideOverlay = options.hideOverlay,
+    showOverlay = options.showOverlay;
+  var overlayMachine = createMachine({
+    initial: "hidden",
+    context: {
+      level: "error",
+      messages: [],
+      messageSource: "build"
+    },
+    states: {
+      hidden: {
+        on: {
+          BUILD_ERROR: {
+            target: "displayBuildError",
+            actions: ["setMessages", "showOverlay"]
+          },
+          RUNTIME_ERROR: {
+            target: "displayRuntimeError",
+            actions: ["setMessages", "showOverlay"]
+          }
+        }
+      },
+      displayBuildError: {
+        on: {
+          DISMISS: {
+            target: "hidden",
+            actions: ["dismissMessages", "hideOverlay"]
+          },
+          BUILD_ERROR: {
+            target: "displayBuildError",
+            actions: ["appendMessages", "showOverlay"]
+          }
+        }
+      },
+      displayRuntimeError: {
+        on: {
+          DISMISS: {
+            target: "hidden",
+            actions: ["dismissMessages", "hideOverlay"]
+          },
+          RUNTIME_ERROR: {
+            target: "displayRuntimeError",
+            actions: ["appendMessages", "showOverlay"]
+          },
+          BUILD_ERROR: {
+            target: "displayBuildError",
+            actions: ["setMessages", "showOverlay"]
+          }
+        }
+      }
+    }
+  }, {
+    actions: {
+      dismissMessages: function dismissMessages() {
+        return {
+          messages: [],
+          level: "error",
+          messageSource: "build"
+        };
+      },
+      appendMessages: function appendMessages(context, event) {
+        return {
+          messages: context.messages.concat(event.messages),
+          level: event.level || context.level,
+          messageSource: event.type === "RUNTIME_ERROR" ? "runtime" : "build"
+        };
+      },
+      setMessages: function setMessages(context, event) {
+        return {
+          messages: event.messages,
+          level: event.level || context.level,
+          messageSource: event.type === "RUNTIME_ERROR" ? "runtime" : "build"
+        };
+      },
+      hideOverlay: hideOverlay,
+      showOverlay: showOverlay
+    }
+  });
+  return overlayMachine;
+};
+export default createOverlayMachine;
Index: frontend/node_modules/webpack-dev-server/client/overlay/styles.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/overlay/styles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/overlay/styles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,74 @@
+// styles are inspired by `react-error-overlay`
+
+var msgStyles = {
+  error: {
+    backgroundColor: "rgba(206, 17, 38, 0.1)",
+    color: "#fccfcf"
+  },
+  warning: {
+    backgroundColor: "rgba(251, 245, 180, 0.1)",
+    color: "#fbf5b4"
+  }
+};
+var iframeStyle = {
+  position: "fixed",
+  top: 0,
+  left: 0,
+  right: 0,
+  bottom: 0,
+  width: "100vw",
+  height: "100vh",
+  border: "none",
+  "z-index": 9999999999
+};
+var containerStyle = {
+  position: "fixed",
+  boxSizing: "border-box",
+  left: 0,
+  top: 0,
+  right: 0,
+  bottom: 0,
+  width: "100vw",
+  height: "100vh",
+  fontSize: "large",
+  padding: "2rem 2rem 4rem 2rem",
+  lineHeight: "1.2",
+  whiteSpace: "pre-wrap",
+  overflow: "auto",
+  backgroundColor: "rgba(0, 0, 0, 0.9)",
+  color: "white"
+};
+var headerStyle = {
+  color: "#e83b46",
+  fontSize: "2em",
+  whiteSpace: "pre-wrap",
+  fontFamily: "sans-serif",
+  margin: "0 2rem 2rem 0",
+  flex: "0 0 auto",
+  maxHeight: "50%",
+  overflow: "auto"
+};
+var dismissButtonStyle = {
+  color: "#ffffff",
+  lineHeight: "1rem",
+  fontSize: "1.5rem",
+  padding: "1rem",
+  cursor: "pointer",
+  position: "absolute",
+  right: 0,
+  top: 0,
+  backgroundColor: "transparent",
+  border: "none"
+};
+var msgTypeStyle = {
+  color: "#e83b46",
+  fontSize: "1.2em",
+  marginBottom: "1rem",
+  fontFamily: "sans-serif"
+};
+var msgTextStyle = {
+  lineHeight: "1.5",
+  fontSize: "1rem",
+  fontFamily: "Menlo, Consolas, monospace"
+};
+export { msgStyles, iframeStyle, containerStyle, headerStyle, dismissButtonStyle, msgTypeStyle, msgTextStyle };
Index: frontend/node_modules/webpack-dev-server/client/socket.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/socket.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/socket.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,66 @@
+/* global __webpack_dev_server_client__ */
+
+import WebSocketClient from "./clients/WebSocketClient.js";
+import { log } from "./utils/log.js";
+
+// this WebsocketClient is here as a default fallback, in case the client is not injected
+/* eslint-disable camelcase */
+var Client =
+// eslint-disable-next-line no-nested-ternary
+typeof __webpack_dev_server_client__ !== "undefined" ? typeof __webpack_dev_server_client__.default !== "undefined" ? __webpack_dev_server_client__.default : __webpack_dev_server_client__ : WebSocketClient;
+/* eslint-enable camelcase */
+
+var retries = 0;
+var maxRetries = 10;
+
+// Initialized client is exported so external consumers can utilize the same instance
+// It is mutable to enforce singleton
+// eslint-disable-next-line import/no-mutable-exports
+export var client = null;
+
+/**
+ * @param {string} url
+ * @param {{ [handler: string]: (data?: any, params?: any) => any }} handlers
+ * @param {number} [reconnect]
+ */
+var socket = function initSocket(url, handlers, reconnect) {
+  client = new Client(url);
+  client.onOpen(function () {
+    retries = 0;
+    if (typeof reconnect !== "undefined") {
+      maxRetries = reconnect;
+    }
+  });
+  client.onClose(function () {
+    if (retries === 0) {
+      handlers.close();
+    }
+
+    // Try to reconnect.
+    client = null;
+
+    // After 10 retries stop trying, to prevent logspam.
+    if (retries < maxRetries) {
+      // Exponentially increase timeout to reconnect.
+      // Respectfully copied from the package `got`.
+      // eslint-disable-next-line no-restricted-properties
+      var retryInMs = 1000 * Math.pow(2, retries) + Math.random() * 100;
+      retries += 1;
+      log.info("Trying to reconnect...");
+      setTimeout(function () {
+        socket(url, handlers, reconnect);
+      }, retryInMs);
+    }
+  });
+  client.onMessage(
+  /**
+   * @param {any} data
+   */
+  function (data) {
+    var message = JSON.parse(data);
+    if (handlers[message.type]) {
+      handlers[message.type](message.data, message.params);
+    }
+  });
+};
+export default socket;
Index: frontend/node_modules/webpack-dev-server/client/utils/createSocketURL.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/createSocketURL.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/createSocketURL.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,121 @@
+/**
+ * @param {{ protocol?: string, auth?: string, hostname?: string, port?: string, pathname?: string, search?: string, hash?: string, slashes?: boolean }} objURL
+ * @returns {string}
+ */
+function format(objURL) {
+  var protocol = objURL.protocol || "";
+  if (protocol && protocol.substr(-1) !== ":") {
+    protocol += ":";
+  }
+  var auth = objURL.auth || "";
+  if (auth) {
+    auth = encodeURIComponent(auth);
+    auth = auth.replace(/%3A/i, ":");
+    auth += "@";
+  }
+  var host = "";
+  if (objURL.hostname) {
+    host = auth + (objURL.hostname.indexOf(":") === -1 ? objURL.hostname : "[".concat(objURL.hostname, "]"));
+    if (objURL.port) {
+      host += ":".concat(objURL.port);
+    }
+  }
+  var pathname = objURL.pathname || "";
+  if (objURL.slashes) {
+    host = "//".concat(host || "");
+    if (pathname && pathname.charAt(0) !== "/") {
+      pathname = "/".concat(pathname);
+    }
+  } else if (!host) {
+    host = "";
+  }
+  var search = objURL.search || "";
+  if (search && search.charAt(0) !== "?") {
+    search = "?".concat(search);
+  }
+  var hash = objURL.hash || "";
+  if (hash && hash.charAt(0) !== "#") {
+    hash = "#".concat(hash);
+  }
+  pathname = pathname.replace(/[?#]/g,
+  /**
+   * @param {string} match
+   * @returns {string}
+   */
+  function (match) {
+    return encodeURIComponent(match);
+  });
+  search = search.replace("#", "%23");
+  return "".concat(protocol).concat(host).concat(pathname).concat(search).concat(hash);
+}
+
+/**
+ * @param {URL & { fromCurrentScript?: boolean }} parsedURL
+ * @returns {string}
+ */
+function createSocketURL(parsedURL) {
+  var hostname = parsedURL.hostname;
+
+  // Node.js module parses it as `::`
+  // `new URL(urlString, [baseURLString])` parses it as '[::]'
+  var isInAddrAny = hostname === "0.0.0.0" || hostname === "::" || hostname === "[::]";
+
+  // why do we need this check?
+  // hostname n/a for file protocol (example, when using electron, ionic)
+  // see: https://github.com/webpack/webpack-dev-server/pull/384
+  if (isInAddrAny && self.location.hostname && self.location.protocol.indexOf("http") === 0) {
+    hostname = self.location.hostname;
+  }
+  var socketURLProtocol = parsedURL.protocol || self.location.protocol;
+
+  // When https is used in the app, secure web sockets are always necessary because the browser doesn't accept non-secure web sockets.
+  if (socketURLProtocol === "auto:" || hostname && isInAddrAny && self.location.protocol === "https:") {
+    socketURLProtocol = self.location.protocol;
+  }
+  socketURLProtocol = socketURLProtocol.replace(/^(?:http|.+-extension|file)/i, "ws");
+  var socketURLAuth = "";
+
+  // `new URL(urlString, [baseURLstring])` doesn't have `auth` property
+  // Parse authentication credentials in case we need them
+  if (parsedURL.username) {
+    socketURLAuth = parsedURL.username;
+
+    // Since HTTP basic authentication does not allow empty username,
+    // we only include password if the username is not empty.
+    if (parsedURL.password) {
+      // Result: <username>:<password>
+      socketURLAuth = socketURLAuth.concat(":", parsedURL.password);
+    }
+  }
+
+  // In case the host is a raw IPv6 address, it can be enclosed in
+  // the brackets as the brackets are needed in the final URL string.
+  // Need to remove those as url.format blindly adds its own set of brackets
+  // if the host string contains colons. That would lead to non-working
+  // double brackets (e.g. [[::]]) host
+  //
+  // All of these web socket url params are optionally passed in through resourceQuery,
+  // so we need to fall back to the default if they are not provided
+  var socketURLHostname = (hostname || self.location.hostname || "localhost").replace(/^\[(.*)\]$/, "$1");
+  var socketURLPort = parsedURL.port;
+  if (!socketURLPort || socketURLPort === "0") {
+    socketURLPort = self.location.port;
+  }
+
+  // If path is provided it'll be passed in via the resourceQuery as a
+  // query param so it has to be parsed out of the querystring in order for the
+  // client to open the socket to the correct location.
+  var socketURLPathname = "/ws";
+  if (parsedURL.pathname && !parsedURL.fromCurrentScript) {
+    socketURLPathname = parsedURL.pathname;
+  }
+  return format({
+    protocol: socketURLProtocol,
+    auth: socketURLAuth,
+    hostname: socketURLHostname,
+    port: socketURLPort,
+    pathname: socketURLPathname,
+    slashes: true
+  });
+}
+export default createSocketURL;
Index: frontend/node_modules/webpack-dev-server/client/utils/getCurrentScriptSource.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/getCurrentScriptSource.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/getCurrentScriptSource.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+/**
+ * @returns {string}
+ */
+function getCurrentScriptSource() {
+  // `document.currentScript` is the most accurate way to find the current script,
+  // but is not supported in all browsers.
+  if (document.currentScript) {
+    return document.currentScript.getAttribute("src");
+  }
+
+  // Fallback to getting all scripts running in the document.
+  var scriptElements = document.scripts || [];
+  var scriptElementsWithSrc = Array.prototype.filter.call(scriptElements, function (element) {
+    return element.getAttribute("src");
+  });
+  if (scriptElementsWithSrc.length > 0) {
+    var currentScript = scriptElementsWithSrc[scriptElementsWithSrc.length - 1];
+    return currentScript.getAttribute("src");
+  }
+
+  // Fail as there was no script to use.
+  throw new Error("[webpack-dev-server] Failed to get current script source.");
+}
+export default getCurrentScriptSource;
Index: frontend/node_modules/webpack-dev-server/client/utils/log.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/log.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/log.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+import logger from "../modules/logger/index.js";
+var name = "webpack-dev-server";
+// default level is set on the client side, so it does not need
+// to be set by the CLI or API
+var defaultLevel = "info";
+
+// options new options, merge with old options
+/**
+ * @param {false | true | "none" | "error" | "warn" | "info" | "log" | "verbose"} level
+ * @returns {void}
+ */
+function setLogLevel(level) {
+  logger.configureDefaultLogger({
+    level: level
+  });
+}
+setLogLevel(defaultLevel);
+var log = logger.getLogger(name);
+var logEnabledFeatures = function logEnabledFeatures(features) {
+  var enabledFeatures = Object.keys(features);
+  if (!features || enabledFeatures.length === 0) {
+    return;
+  }
+  var logString = "Server started:";
+
+  // Server started: Hot Module Replacement enabled, Live Reloading enabled, Overlay disabled.
+  for (var i = 0; i < enabledFeatures.length; i++) {
+    var key = enabledFeatures[i];
+    logString += " ".concat(key, " ").concat(features[key] ? "enabled" : "disabled", ",");
+  }
+  // replace last comma with a period
+  logString = logString.slice(0, -1).concat(".");
+  log.info(logString);
+};
+export { log, logEnabledFeatures, setLogLevel };
Index: frontend/node_modules/webpack-dev-server/client/utils/parseURL.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/parseURL.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/parseURL.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,36 @@
+import getCurrentScriptSource from "./getCurrentScriptSource.js";
+
+/**
+ * @param {string} resourceQuery
+ * @returns {{ [key: string]: string | boolean }}
+ */
+function parseURL(resourceQuery) {
+  /** @type {{ [key: string]: string }} */
+  var options = {};
+  if (typeof resourceQuery === "string" && resourceQuery !== "") {
+    var searchParams = resourceQuery.slice(1).split("&");
+    for (var i = 0; i < searchParams.length; i++) {
+      var pair = searchParams[i].split("=");
+      options[pair[0]] = decodeURIComponent(pair[1]);
+    }
+  } else {
+    // Else, get the url from the <script> this file was called with.
+    var scriptSource = getCurrentScriptSource();
+    var scriptSourceURL;
+    try {
+      // The placeholder `baseURL` with `window.location.href`,
+      // is to allow parsing of path-relative or protocol-relative URLs,
+      // and will have no effect if `scriptSource` is a fully valid URL.
+      scriptSourceURL = new URL(scriptSource, self.location.href);
+    } catch (error) {
+      // URL parsing failed, do nothing.
+      // We will still proceed to see if we can recover using `resourceQuery`
+    }
+    if (scriptSourceURL) {
+      options = scriptSourceURL;
+      options.fromCurrentScript = true;
+    }
+  }
+  return options;
+}
+export default parseURL;
Index: frontend/node_modules/webpack-dev-server/client/utils/reloadApp.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/reloadApp.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/reloadApp.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,63 @@
+import hotEmitter from "webpack/hot/emitter.js";
+import { log } from "./log.js";
+
+/** @typedef {import("../index").Options} Options
+/** @typedef {import("../index").Status} Status
+
+/**
+ * @param {Options} options
+ * @param {Status} status
+ */
+function reloadApp(_ref, status) {
+  var hot = _ref.hot,
+    liveReload = _ref.liveReload;
+  if (status.isUnloading) {
+    return;
+  }
+  var currentHash = status.currentHash,
+    previousHash = status.previousHash;
+  var isInitial = currentHash.indexOf( /** @type {string} */previousHash) >= 0;
+  if (isInitial) {
+    return;
+  }
+
+  /**
+   * @param {Window} rootWindow
+   * @param {number} intervalId
+   */
+  function applyReload(rootWindow, intervalId) {
+    clearInterval(intervalId);
+    log.info("App updated. Reloading...");
+    rootWindow.location.reload();
+  }
+  var search = self.location.search.toLowerCase();
+  var allowToHot = search.indexOf("webpack-dev-server-hot=false") === -1;
+  var allowToLiveReload = search.indexOf("webpack-dev-server-live-reload=false") === -1;
+  if (hot && allowToHot) {
+    log.info("App hot update...");
+    hotEmitter.emit("webpackHotUpdate", status.currentHash);
+    if (typeof self !== "undefined" && self.window) {
+      // broadcast update to window
+      self.postMessage("webpackHotUpdate".concat(status.currentHash), "*");
+    }
+  }
+  // allow refreshing the page only if liveReload isn't disabled
+  else if (liveReload && allowToLiveReload) {
+    var rootWindow = self;
+
+    // use parent window for reload (in case we're in an iframe with no valid src)
+    var intervalId = self.setInterval(function () {
+      if (rootWindow.location.protocol !== "about:") {
+        // reload immediately if protocol is valid
+        applyReload(rootWindow, intervalId);
+      } else {
+        rootWindow = rootWindow.parent;
+        if (rootWindow.parent === rootWindow) {
+          // if parent equals current window we've reached the root which would continue forever, so trigger a reload anyways
+          applyReload(rootWindow, intervalId);
+        }
+      }
+    });
+  }
+}
+export default reloadApp;
Index: frontend/node_modules/webpack-dev-server/client/utils/sendMessage.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/sendMessage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/sendMessage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+/* global __resourceQuery WorkerGlobalScope */
+
+// Send messages to the outside, so plugins can consume it.
+/**
+ * @param {string} type
+ * @param {any} [data]
+ */
+function sendMsg(type, data) {
+  if (typeof self !== "undefined" && (typeof WorkerGlobalScope === "undefined" || !(self instanceof WorkerGlobalScope))) {
+    self.postMessage({
+      type: "webpack".concat(type),
+      data: data
+    }, "*");
+  }
+}
+export default sendMsg;
Index: frontend/node_modules/webpack-dev-server/client/utils/stripAnsi.js
===================================================================
--- frontend/node_modules/webpack-dev-server/client/utils/stripAnsi.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/client/utils/stripAnsi.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+var ansiRegex = new RegExp(["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|"), "g");
+
+/**
+ *
+ * Strip [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) from a string.
+ * Adapted from code originally released by Sindre Sorhus
+ * Licensed the MIT License
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function stripAnsi(string) {
+  if (typeof string !== "string") {
+    throw new TypeError("Expected a `string`, got `".concat(typeof string, "`"));
+  }
+  return string.replace(ansiRegex, "");
+}
+export default stripAnsi;
Index: frontend/node_modules/webpack-dev-server/lib/Server.js
===================================================================
--- frontend/node_modules/webpack-dev-server/lib/Server.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/lib/Server.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3593 @@
+"use strict";
+
+const os = require("os");
+const path = require("path");
+const url = require("url");
+const util = require("util");
+const fs = require("graceful-fs");
+const ipaddr = require("ipaddr.js");
+const { validate } = require("schema-utils");
+const schema = require("./options.json");
+
+/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
+/** @typedef {import("webpack").Compiler} Compiler */
+/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
+/** @typedef {import("webpack").Configuration} WebpackConfiguration */
+/** @typedef {import("webpack").StatsOptions} StatsOptions */
+/** @typedef {import("webpack").StatsCompilation} StatsCompilation */
+/** @typedef {import("webpack").Stats} Stats */
+/** @typedef {import("webpack").MultiStats} MultiStats */
+/** @typedef {import("os").NetworkInterfaceInfo} NetworkInterfaceInfo */
+/** @typedef {import("express").Request} Request */
+/** @typedef {import("express").Response} Response */
+/** @typedef {import("express").NextFunction} NextFunction */
+/** @typedef {import("express").RequestHandler} ExpressRequestHandler */
+/** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
+/** @typedef {import("chokidar").WatchOptions} WatchOptions */
+/** @typedef {import("chokidar").FSWatcher} FSWatcher */
+/** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
+/** @typedef {import("bonjour-service").Bonjour} Bonjour */
+/** @typedef {import("bonjour-service").Service} BonjourOptions */
+/** @typedef {import("http-proxy-middleware").RequestHandler} RequestHandler */
+/** @typedef {import("http-proxy-middleware").Options} HttpProxyMiddlewareOptions */
+/** @typedef {import("http-proxy-middleware").Filter} HttpProxyMiddlewareOptionsFilter */
+/** @typedef {import("serve-index").Options} ServeIndexOptions */
+/** @typedef {import("serve-static").ServeStaticOptions} ServeStaticOptions */
+/** @typedef {import("ipaddr.js").IPv4} IPv4 */
+/** @typedef {import("ipaddr.js").IPv6} IPv6 */
+/** @typedef {import("net").Socket} Socket */
+/** @typedef {import("http").IncomingMessage} IncomingMessage */
+/** @typedef {import("open").Options} OpenOptions */
+
+/** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
+
+/**
+ * @template Request, Response
+ * @typedef {import("webpack-dev-middleware").Options<Request, Response>} DevMiddlewareOptions
+ */
+
+/**
+ * @template Request, Response
+ * @typedef {import("webpack-dev-middleware").Context<Request, Response>} DevMiddlewareContext
+ */
+
+/**
+ * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host
+ */
+
+/**
+ * @typedef {number | string | "auto"} Port
+ */
+
+/**
+ * @typedef {Object} WatchFiles
+ * @property {string | string[]} paths
+ * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
+ */
+
+/**
+ * @typedef {Object} Static
+ * @property {string} [directory]
+ * @property {string | string[]} [publicPath]
+ * @property {boolean | ServeIndexOptions} [serveIndex]
+ * @property {ServeStaticOptions} [staticOptions]
+ * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
+ */
+
+/**
+ * @typedef {Object} NormalizedStatic
+ * @property {string} directory
+ * @property {string[]} publicPath
+ * @property {false | ServeIndexOptions} serveIndex
+ * @property {ServeStaticOptions} staticOptions
+ * @property {false | WatchOptions} watch
+ */
+
+/**
+ * @typedef {Object} ServerConfiguration
+ * @property {"http" | "https" | "spdy" | string} [type]
+ * @property {ServerOptions} [options]
+ */
+
+/**
+ * @typedef {Object} WebSocketServerConfiguration
+ * @property {"sockjs" | "ws" | string | Function} [type]
+ * @property {Record<string, any>} [options]
+ */
+
+/**
+ * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+ */
+
+/**
+ * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+ */
+
+/**
+ * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+ */
+
+/**
+ * @callback ByPass
+ * @param {Request} req
+ * @param {Response} res
+ * @param {ProxyConfigArrayItem} proxyConfig
+ */
+
+/**
+ * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+ */
+
+/**
+ * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+ */
+
+/**
+ * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+ */
+
+/**
+ * @typedef {Object} OpenApp
+ * @property {string} [name]
+ * @property {string[]} [arguments]
+ */
+
+/**
+ * @typedef {Object} Open
+ * @property {string | string[] | OpenApp} [app]
+ * @property {string | string[]} [target]
+ */
+
+/**
+ * @typedef {Object} NormalizedOpen
+ * @property {string} target
+ * @property {import("open").Options} options
+ */
+
+/**
+ * @typedef {Object} WebSocketURL
+ * @property {string} [hostname]
+ * @property {string} [password]
+ * @property {string} [pathname]
+ * @property {number | string} [port]
+ * @property {string} [protocol]
+ * @property {string} [username]
+ */
+
+/**
+ * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+ */
+
+/**
+ * @typedef {Object} ClientConfiguration
+ * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+ * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+ * @property {boolean} [progress]
+ * @property {boolean | number} [reconnect]
+ * @property {"ws" | "sockjs" | string} [webSocketTransport]
+ * @property {string | WebSocketURL} [webSocketURL]
+ */
+
+/**
+ * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+ */
+
+/**
+ * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+ */
+
+/**
+ * @typedef {Object} Configuration
+ * @property {boolean | string} [ipc]
+ * @property {Host} [host]
+ * @property {Port} [port]
+ * @property {boolean | "only"} [hot]
+ * @property {boolean} [liveReload]
+ * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+ * @property {boolean} [compress]
+ * @property {boolean} [magicHtml]
+ * @property {"auto" | "all" | string | string[]} [allowedHosts]
+ * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+ * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+ * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+ * @property {boolean | string | Static | Array<string | Static>} [static]
+ * @property {boolean | ServerOptions} [https]
+ * @property {boolean} [http2]
+ * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+ * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+ * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+ * @property {boolean | string | Open | Array<string | Open>} [open]
+ * @property {boolean} [setupExitSignals]
+ * @property {boolean | ClientConfiguration} [client]
+ * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+ * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+ * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+ * @property {(devServer: Server) => void} [onListening]
+ * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+ */
+
+if (!process.env.WEBPACK_SERVE) {
+  // TODO fix me in the next major release
+  // @ts-ignore
+  process.env.WEBPACK_SERVE = true;
+}
+
+/**
+ * @template T
+ * @param fn {(function(): any) | undefined}
+ * @returns {function(): T}
+ */
+const memoize = (fn) => {
+  let cache = false;
+  /** @type {T} */
+  let result;
+
+  return () => {
+    if (cache) {
+      return result;
+    }
+
+    result = /** @type {function(): any} */ (fn)();
+    cache = true;
+    // Allow to clean up memory for fn
+    // and all dependent resources
+    // eslint-disable-next-line no-undefined
+    fn = undefined;
+
+    return result;
+  };
+};
+
+const getExpress = memoize(() => require("express"));
+
+/**
+ *
+ * @param {OverlayMessageOptions} [setting]
+ * @returns
+ */
+const encodeOverlaySettings = (setting) =>
+  typeof setting === "function"
+    ? encodeURIComponent(setting.toString())
+    : setting;
+
+class Server {
+  /**
+   * @param {Configuration | Compiler | MultiCompiler} options
+   * @param {Compiler | MultiCompiler | Configuration} compiler
+   */
+  constructor(options = {}, compiler) {
+    // TODO: remove this after plugin support is published
+    if (/** @type {Compiler | MultiCompiler} */ (options).hooks) {
+      util.deprecate(
+        () => {},
+        "Using 'compiler' as the first argument is deprecated. Please use 'options' as the first argument and 'compiler' as the second argument.",
+        "DEP_WEBPACK_DEV_SERVER_CONSTRUCTOR"
+      )();
+
+      [options = {}, compiler] = [compiler, options];
+    }
+
+    validate(/** @type {Schema} */ (schema), options, {
+      name: "Dev Server",
+      baseDataPath: "options",
+    });
+
+    this.compiler = /** @type {Compiler | MultiCompiler} */ (compiler);
+    /**
+     * @type {ReturnType<Compiler["getInfrastructureLogger"]>}
+     * */
+    this.logger = this.compiler.getInfrastructureLogger("webpack-dev-server");
+    this.options = /** @type {Configuration} */ (options);
+    /**
+     * @type {FSWatcher[]}
+     */
+    this.staticWatchers = [];
+    /**
+     * @private
+     * @type {{ name: string | symbol, listener: (...args: any[]) => void}[] }}
+     */
+    this.listeners = [];
+    // Keep track of websocket proxies for external websocket upgrade.
+    /**
+     * @private
+     * @type {RequestHandler[]}
+     */
+    this.webSocketProxies = [];
+    /**
+     * @type {Socket[]}
+     */
+    this.sockets = [];
+    /**
+     * @private
+     * @type {string | undefined}
+     */
+    // eslint-disable-next-line no-undefined
+    this.currentHash = undefined;
+  }
+
+  // TODO compatibility with webpack v4, remove it after drop
+  static get cli() {
+    return {
+      get getArguments() {
+        return () => require("../bin/cli-flags");
+      },
+      get processArguments() {
+        return require("../bin/process-arguments");
+      },
+    };
+  }
+
+  static get schema() {
+    return schema;
+  }
+
+  /**
+   * @private
+   * @returns {StatsOptions}
+   * @constructor
+   */
+  static get DEFAULT_STATS() {
+    return {
+      all: false,
+      hash: true,
+      warnings: true,
+      errors: true,
+      errorDetails: false,
+    };
+  }
+
+  /**
+   * @param {string} URL
+   * @returns {boolean}
+   */
+  static isAbsoluteURL(URL) {
+    // Don't match Windows paths `c:\`
+    if (/^[a-zA-Z]:\\/.test(URL)) {
+      return false;
+    }
+
+    // Scheme: https://tools.ietf.org/html/rfc3986#section-3.1
+    // Absolute URL: https://tools.ietf.org/html/rfc3986#section-4.3
+    return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(URL);
+  }
+
+  /**
+   * @param {string} gateway
+   * @returns {string | undefined}
+   */
+  static findIp(gateway) {
+    const gatewayIp = ipaddr.parse(gateway);
+
+    // Look for the matching interface in all local interfaces.
+    for (const addresses of Object.values(os.networkInterfaces())) {
+      for (const { cidr } of /** @type {NetworkInterfaceInfo[]} */ (
+        addresses
+      )) {
+        const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));
+
+        if (
+          net[0] &&
+          net[0].kind() === gatewayIp.kind() &&
+          gatewayIp.match(net)
+        ) {
+          return net[0].toString();
+        }
+      }
+    }
+  }
+
+  /**
+   * @param {"v4" | "v6"} family
+   * @returns {Promise<string | undefined>}
+   */
+  static async internalIP(family) {
+    try {
+      const { gateway } = await require("default-gateway")[family]();
+      return Server.findIp(gateway);
+    } catch {
+      // ignore
+    }
+  }
+
+  /**
+   * @param {"v4" | "v6"} family
+   * @returns {string | undefined}
+   */
+  static internalIPSync(family) {
+    try {
+      const { gateway } = require("default-gateway")[family].sync();
+      return Server.findIp(gateway);
+    } catch {
+      // ignore
+    }
+  }
+
+  /**
+   * @param {Host} hostname
+   * @returns {Promise<string>}
+   */
+  static async getHostname(hostname) {
+    if (hostname === "local-ip") {
+      return (
+        (await Server.internalIP("v4")) ||
+        (await Server.internalIP("v6")) ||
+        "0.0.0.0"
+      );
+    } else if (hostname === "local-ipv4") {
+      return (await Server.internalIP("v4")) || "0.0.0.0";
+    } else if (hostname === "local-ipv6") {
+      return (await Server.internalIP("v6")) || "::";
+    }
+
+    return hostname;
+  }
+
+  /**
+   * @param {Port} port
+   * @param {string} host
+   * @returns {Promise<number | string>}
+   */
+  static async getFreePort(port, host) {
+    if (typeof port !== "undefined" && port !== null && port !== "auto") {
+      return port;
+    }
+
+    const pRetry = require("p-retry");
+    const getPort = require("./getPort");
+    const basePort =
+      typeof process.env.WEBPACK_DEV_SERVER_BASE_PORT !== "undefined"
+        ? parseInt(process.env.WEBPACK_DEV_SERVER_BASE_PORT, 10)
+        : 8080;
+
+    // Try to find unused port and listen on it for 3 times,
+    // if port is not specified in options.
+    const defaultPortRetry =
+      typeof process.env.WEBPACK_DEV_SERVER_PORT_RETRY !== "undefined"
+        ? parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10)
+        : 3;
+
+    return pRetry(() => getPort(basePort, host), {
+      retries: defaultPortRetry,
+    });
+  }
+
+  /**
+   * @returns {string}
+   */
+  static findCacheDir() {
+    const cwd = process.cwd();
+
+    /**
+     * @type {string | undefined}
+     */
+    let dir = cwd;
+
+    for (;;) {
+      try {
+        if (fs.statSync(path.join(dir, "package.json")).isFile()) break;
+        // eslint-disable-next-line no-empty
+      } catch (e) {}
+
+      const parent = path.dirname(dir);
+
+      if (dir === parent) {
+        // eslint-disable-next-line no-undefined
+        dir = undefined;
+        break;
+      }
+
+      dir = parent;
+    }
+
+    if (!dir) {
+      return path.resolve(cwd, ".cache/webpack-dev-server");
+    } else if (process.versions.pnp === "1") {
+      return path.resolve(dir, ".pnp/.cache/webpack-dev-server");
+    } else if (process.versions.pnp === "3") {
+      return path.resolve(dir, ".yarn/.cache/webpack-dev-server");
+    }
+
+    return path.resolve(dir, "node_modules/.cache/webpack-dev-server");
+  }
+
+  /**
+   * @private
+   * @param {Compiler} compiler
+   * @returns bool
+   */
+  static isWebTarget(compiler) {
+    // TODO improve for the next major version - we should store `web` and other targets in `compiler.options.environment`
+    if (
+      compiler.options.externalsPresets &&
+      compiler.options.externalsPresets.web
+    ) {
+      return true;
+    }
+
+    if (
+      compiler.options.resolve.conditionNames &&
+      compiler.options.resolve.conditionNames.includes("browser")
+    ) {
+      return true;
+    }
+
+    const webTargets = [
+      "web",
+      "webworker",
+      "electron-preload",
+      "electron-renderer",
+      "node-webkit",
+      // eslint-disable-next-line no-undefined
+      undefined,
+      null,
+    ];
+
+    if (Array.isArray(compiler.options.target)) {
+      return compiler.options.target.some((r) => webTargets.includes(r));
+    }
+
+    return webTargets.includes(/** @type {string} */ (compiler.options.target));
+  }
+
+  /**
+   * @private
+   * @param {Compiler} compiler
+   */
+  addAdditionalEntries(compiler) {
+    /**
+     * @type {string[]}
+     */
+    const additionalEntries = [];
+    const isWebTarget = Server.isWebTarget(compiler);
+
+    // TODO maybe empty client
+    if (this.options.client && isWebTarget) {
+      let webSocketURLStr = "";
+
+      if (this.options.webSocketServer) {
+        const webSocketURL =
+          /** @type {WebSocketURL} */
+          (
+            /** @type {ClientConfiguration} */
+            (this.options.client).webSocketURL
+          );
+        const webSocketServer =
+          /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable<WebSocketServerConfiguration["options"]> }} */
+          (this.options.webSocketServer);
+        const searchParams = new URLSearchParams();
+
+        /** @type {string} */
+        let protocol;
+
+        // We are proxying dev server and need to specify custom `hostname`
+        if (typeof webSocketURL.protocol !== "undefined") {
+          protocol = webSocketURL.protocol;
+        } else {
+          protocol =
+            /** @type {ServerConfiguration} */
+            (this.options.server).type === "http" ? "ws:" : "wss:";
+        }
+
+        searchParams.set("protocol", protocol);
+
+        if (typeof webSocketURL.username !== "undefined") {
+          searchParams.set("username", webSocketURL.username);
+        }
+
+        if (typeof webSocketURL.password !== "undefined") {
+          searchParams.set("password", webSocketURL.password);
+        }
+
+        /** @type {string} */
+        let hostname;
+
+        // SockJS is not supported server mode, so `hostname` and `port` can't specified, let's ignore them
+        // TODO show warning about this
+        const isSockJSType = webSocketServer.type === "sockjs";
+
+        // We are proxying dev server and need to specify custom `hostname`
+        if (typeof webSocketURL.hostname !== "undefined") {
+          hostname = webSocketURL.hostname;
+        }
+        // Web socket server works on custom `hostname`, only for `ws` because `sock-js` is not support custom `hostname`
+        else if (
+          typeof webSocketServer.options.host !== "undefined" &&
+          !isSockJSType
+        ) {
+          hostname = webSocketServer.options.host;
+        }
+        // The `host` option is specified
+        else if (typeof this.options.host !== "undefined") {
+          hostname = this.options.host;
+        }
+        // The `port` option is not specified
+        else {
+          hostname = "0.0.0.0";
+        }
+
+        searchParams.set("hostname", hostname);
+
+        /** @type {number | string} */
+        let port;
+
+        // We are proxying dev server and need to specify custom `port`
+        if (typeof webSocketURL.port !== "undefined") {
+          port = webSocketURL.port;
+        }
+        // Web socket server works on custom `port`, only for `ws` because `sock-js` is not support custom `port`
+        else if (
+          typeof webSocketServer.options.port !== "undefined" &&
+          !isSockJSType
+        ) {
+          port = webSocketServer.options.port;
+        }
+        // The `port` option is specified
+        else if (typeof this.options.port === "number") {
+          port = this.options.port;
+        }
+        // The `port` option is specified using `string`
+        else if (
+          typeof this.options.port === "string" &&
+          this.options.port !== "auto"
+        ) {
+          port = Number(this.options.port);
+        }
+        // The `port` option is not specified or set to `auto`
+        else {
+          port = "0";
+        }
+
+        searchParams.set("port", String(port));
+
+        /** @type {string} */
+        let pathname = "";
+
+        // We are proxying dev server and need to specify custom `pathname`
+        if (typeof webSocketURL.pathname !== "undefined") {
+          pathname = webSocketURL.pathname;
+        }
+        // Web socket server works on custom `path`
+        else if (
+          typeof webSocketServer.options.prefix !== "undefined" ||
+          typeof webSocketServer.options.path !== "undefined"
+        ) {
+          pathname =
+            webSocketServer.options.prefix || webSocketServer.options.path;
+        }
+
+        searchParams.set("pathname", pathname);
+
+        const client = /** @type {ClientConfiguration} */ (this.options.client);
+
+        if (typeof client.logging !== "undefined") {
+          searchParams.set("logging", client.logging);
+        }
+
+        if (typeof client.progress !== "undefined") {
+          searchParams.set("progress", String(client.progress));
+        }
+
+        if (typeof client.overlay !== "undefined") {
+          const overlayString =
+            typeof client.overlay === "boolean"
+              ? String(client.overlay)
+              : JSON.stringify({
+                  ...client.overlay,
+                  errors: encodeOverlaySettings(client.overlay.errors),
+                  warnings: encodeOverlaySettings(client.overlay.warnings),
+                  runtimeErrors: encodeOverlaySettings(
+                    client.overlay.runtimeErrors
+                  ),
+                });
+
+          searchParams.set("overlay", overlayString);
+        }
+
+        if (typeof client.reconnect !== "undefined") {
+          searchParams.set(
+            "reconnect",
+            typeof client.reconnect === "number"
+              ? String(client.reconnect)
+              : "10"
+          );
+        }
+
+        if (typeof this.options.hot !== "undefined") {
+          searchParams.set("hot", String(this.options.hot));
+        }
+
+        if (typeof this.options.liveReload !== "undefined") {
+          searchParams.set("live-reload", String(this.options.liveReload));
+        }
+
+        webSocketURLStr = searchParams.toString();
+      }
+
+      additionalEntries.push(
+        `${require.resolve("../client/index.js")}?${webSocketURLStr}`
+      );
+    }
+
+    if (this.options.hot === "only") {
+      additionalEntries.push(require.resolve("webpack/hot/only-dev-server"));
+    } else if (this.options.hot) {
+      additionalEntries.push(require.resolve("webpack/hot/dev-server"));
+    }
+
+    const webpack = compiler.webpack || require("webpack");
+
+    // use a hook to add entries if available
+    if (typeof webpack.EntryPlugin !== "undefined") {
+      for (const additionalEntry of additionalEntries) {
+        new webpack.EntryPlugin(compiler.context, additionalEntry, {
+          // eslint-disable-next-line no-undefined
+          name: undefined,
+        }).apply(compiler);
+      }
+    }
+    // TODO remove after drop webpack v4 support
+    else {
+      /**
+       * prependEntry Method for webpack 4
+       * @param {any} originalEntry
+       * @param {any} newAdditionalEntries
+       * @returns {any}
+       */
+      const prependEntry = (originalEntry, newAdditionalEntries) => {
+        if (typeof originalEntry === "function") {
+          return () =>
+            Promise.resolve(originalEntry()).then((entry) =>
+              prependEntry(entry, newAdditionalEntries)
+            );
+        }
+
+        if (
+          typeof originalEntry === "object" &&
+          !Array.isArray(originalEntry)
+        ) {
+          /** @type {Object<string,string>} */
+          const clone = {};
+
+          Object.keys(originalEntry).forEach((key) => {
+            // entry[key] should be a string here
+            const entryDescription = originalEntry[key];
+
+            clone[key] = prependEntry(entryDescription, newAdditionalEntries);
+          });
+
+          return clone;
+        }
+
+        // in this case, entry is a string or an array.
+        // make sure that we do not add duplicates.
+        /** @type {any} */
+        const entriesClone = additionalEntries.slice(0);
+
+        [].concat(originalEntry).forEach((newEntry) => {
+          if (!entriesClone.includes(newEntry)) {
+            entriesClone.push(newEntry);
+          }
+        });
+
+        return entriesClone;
+      };
+
+      compiler.options.entry = prependEntry(
+        compiler.options.entry || "./src",
+        additionalEntries
+      );
+      compiler.hooks.entryOption.call(
+        /** @type {string} */ (compiler.options.context),
+        compiler.options.entry
+      );
+    }
+  }
+
+  /**
+   * @private
+   * @returns {Compiler["options"]}
+   */
+  getCompilerOptions() {
+    if (
+      typeof (/** @type {MultiCompiler} */ (this.compiler).compilers) !==
+      "undefined"
+    ) {
+      if (/** @type {MultiCompiler} */ (this.compiler).compilers.length === 1) {
+        return (
+          /** @type {MultiCompiler} */
+          (this.compiler).compilers[0].options
+        );
+      }
+
+      // Configuration with the `devServer` options
+      const compilerWithDevServer =
+        /** @type {MultiCompiler} */
+        (this.compiler).compilers.find((config) => config.options.devServer);
+
+      if (compilerWithDevServer) {
+        return compilerWithDevServer.options;
+      }
+
+      // Configuration with `web` preset
+      const compilerWithWebPreset =
+        /** @type {MultiCompiler} */
+        (this.compiler).compilers.find(
+          (config) =>
+            (config.options.externalsPresets &&
+              config.options.externalsPresets.web) ||
+            [
+              "web",
+              "webworker",
+              "electron-preload",
+              "electron-renderer",
+              "node-webkit",
+              // eslint-disable-next-line no-undefined
+              undefined,
+              null,
+            ].includes(/** @type {string} */ (config.options.target))
+        );
+
+      if (compilerWithWebPreset) {
+        return compilerWithWebPreset.options;
+      }
+
+      // Fallback
+      return /** @type {MultiCompiler} */ (this.compiler).compilers[0].options;
+    }
+
+    return /** @type {Compiler} */ (this.compiler).options;
+  }
+
+  /**
+   * @private
+   * @returns {Promise<void>}
+   */
+  async normalizeOptions() {
+    const { options } = this;
+    const compilerOptions = this.getCompilerOptions();
+    // TODO remove `{}` after drop webpack v4 support
+    const compilerWatchOptions = compilerOptions.watchOptions || {};
+    /**
+     * @param {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} watchOptions
+     * @returns {WatchOptions}
+     */
+    const getWatchOptions = (watchOptions = {}) => {
+      const getPolling = () => {
+        if (typeof watchOptions.usePolling !== "undefined") {
+          return watchOptions.usePolling;
+        }
+
+        if (typeof watchOptions.poll !== "undefined") {
+          return Boolean(watchOptions.poll);
+        }
+
+        if (typeof compilerWatchOptions.poll !== "undefined") {
+          return Boolean(compilerWatchOptions.poll);
+        }
+
+        return false;
+      };
+      const getInterval = () => {
+        if (typeof watchOptions.interval !== "undefined") {
+          return watchOptions.interval;
+        }
+
+        if (typeof watchOptions.poll === "number") {
+          return watchOptions.poll;
+        }
+
+        if (typeof compilerWatchOptions.poll === "number") {
+          return compilerWatchOptions.poll;
+        }
+      };
+
+      const usePolling = getPolling();
+      const interval = getInterval();
+      const { poll, ...rest } = watchOptions;
+
+      return {
+        ignoreInitial: true,
+        persistent: true,
+        followSymlinks: false,
+        atomic: false,
+        alwaysStat: true,
+        ignorePermissionErrors: true,
+        // Respect options from compiler watchOptions
+        usePolling,
+        interval,
+        ignored: watchOptions.ignored,
+        // TODO: we respect these options for all watch options and allow developers to pass them to chokidar, but chokidar doesn't have these options maybe we need revisit that in future
+        ...rest,
+      };
+    };
+    /**
+     * @param {string | Static | undefined} [optionsForStatic]
+     * @returns {NormalizedStatic}
+     */
+    const getStaticItem = (optionsForStatic) => {
+      const getDefaultStaticOptions = () => {
+        return {
+          directory: path.join(process.cwd(), "public"),
+          staticOptions: {},
+          publicPath: ["/"],
+          serveIndex: { icons: true },
+          watch: getWatchOptions(),
+        };
+      };
+
+      /** @type {NormalizedStatic} */
+      let item;
+
+      if (typeof optionsForStatic === "undefined") {
+        item = getDefaultStaticOptions();
+      } else if (typeof optionsForStatic === "string") {
+        item = {
+          ...getDefaultStaticOptions(),
+          directory: optionsForStatic,
+        };
+      } else {
+        const def = getDefaultStaticOptions();
+
+        item = {
+          directory:
+            typeof optionsForStatic.directory !== "undefined"
+              ? optionsForStatic.directory
+              : def.directory,
+          // TODO: do merge in the next major release
+          staticOptions:
+            typeof optionsForStatic.staticOptions !== "undefined"
+              ? optionsForStatic.staticOptions
+              : def.staticOptions,
+          publicPath:
+            // eslint-disable-next-line no-nested-ternary
+            typeof optionsForStatic.publicPath !== "undefined"
+              ? Array.isArray(optionsForStatic.publicPath)
+                ? optionsForStatic.publicPath
+                : [optionsForStatic.publicPath]
+              : def.publicPath,
+          // TODO: do merge in the next major release
+          serveIndex:
+            // eslint-disable-next-line no-nested-ternary
+            typeof optionsForStatic.serveIndex !== "undefined"
+              ? typeof optionsForStatic.serveIndex === "boolean" &&
+                optionsForStatic.serveIndex
+                ? def.serveIndex
+                : optionsForStatic.serveIndex
+              : def.serveIndex,
+          watch:
+            // eslint-disable-next-line no-nested-ternary
+            typeof optionsForStatic.watch !== "undefined"
+              ? // eslint-disable-next-line no-nested-ternary
+                typeof optionsForStatic.watch === "boolean"
+                ? optionsForStatic.watch
+                  ? def.watch
+                  : false
+                : getWatchOptions(optionsForStatic.watch)
+              : def.watch,
+        };
+      }
+
+      if (Server.isAbsoluteURL(item.directory)) {
+        throw new Error("Using a URL as static.directory is not supported");
+      }
+
+      return item;
+    };
+
+    if (typeof options.allowedHosts === "undefined") {
+      // AllowedHosts allows some default hosts picked from `options.host` or `webSocketURL.hostname` and `localhost`
+      options.allowedHosts = "auto";
+    }
+    // We store allowedHosts as array when supplied as string
+    else if (
+      typeof options.allowedHosts === "string" &&
+      options.allowedHosts !== "auto" &&
+      options.allowedHosts !== "all"
+    ) {
+      options.allowedHosts = [options.allowedHosts];
+    }
+    // CLI pass options as array, we should normalize them
+    else if (
+      Array.isArray(options.allowedHosts) &&
+      options.allowedHosts.includes("all")
+    ) {
+      options.allowedHosts = "all";
+    }
+
+    if (typeof options.bonjour === "undefined") {
+      options.bonjour = false;
+    } else if (typeof options.bonjour === "boolean") {
+      options.bonjour = options.bonjour ? {} : false;
+    }
+
+    if (
+      typeof options.client === "undefined" ||
+      (typeof options.client === "object" && options.client !== null)
+    ) {
+      if (!options.client) {
+        options.client = {};
+      }
+
+      if (typeof options.client.webSocketURL === "undefined") {
+        options.client.webSocketURL = {};
+      } else if (typeof options.client.webSocketURL === "string") {
+        const parsedURL = new URL(options.client.webSocketURL);
+
+        options.client.webSocketURL = {
+          protocol: parsedURL.protocol,
+          hostname: parsedURL.hostname,
+          port: parsedURL.port.length > 0 ? Number(parsedURL.port) : "",
+          pathname: parsedURL.pathname,
+          username: parsedURL.username,
+          password: parsedURL.password,
+        };
+      } else if (typeof options.client.webSocketURL.port === "string") {
+        options.client.webSocketURL.port = Number(
+          options.client.webSocketURL.port
+        );
+      }
+
+      // Enable client overlay by default
+      if (typeof options.client.overlay === "undefined") {
+        options.client.overlay = true;
+      } else if (typeof options.client.overlay !== "boolean") {
+        options.client.overlay = {
+          errors: true,
+          warnings: true,
+          ...options.client.overlay,
+        };
+      }
+
+      if (typeof options.client.reconnect === "undefined") {
+        options.client.reconnect = 10;
+      } else if (options.client.reconnect === true) {
+        options.client.reconnect = Infinity;
+      } else if (options.client.reconnect === false) {
+        options.client.reconnect = 0;
+      }
+
+      // Respect infrastructureLogging.level
+      if (typeof options.client.logging === "undefined") {
+        options.client.logging = compilerOptions.infrastructureLogging
+          ? compilerOptions.infrastructureLogging.level
+          : "info";
+      }
+    }
+
+    if (typeof options.compress === "undefined") {
+      options.compress = true;
+    }
+
+    if (typeof options.devMiddleware === "undefined") {
+      options.devMiddleware = {};
+    }
+
+    // No need to normalize `headers`
+
+    if (typeof options.historyApiFallback === "undefined") {
+      options.historyApiFallback = false;
+    } else if (
+      typeof options.historyApiFallback === "boolean" &&
+      options.historyApiFallback
+    ) {
+      options.historyApiFallback = {};
+    }
+
+    // No need to normalize `host`
+
+    options.hot =
+      typeof options.hot === "boolean" || options.hot === "only"
+        ? options.hot
+        : true;
+
+    const isHTTPs = Boolean(options.https);
+    const isSPDY = Boolean(options.http2);
+
+    if (isHTTPs) {
+      // TODO: remove in the next major release
+      util.deprecate(
+        () => {},
+        "'https' option is deprecated. Please use the 'server' option.",
+        "DEP_WEBPACK_DEV_SERVER_HTTPS"
+      )();
+    }
+
+    if (isSPDY) {
+      // TODO: remove in the next major release
+      util.deprecate(
+        () => {},
+        "'http2' option is deprecated. Please use the 'server' option.",
+        "DEP_WEBPACK_DEV_SERVER_HTTP2"
+      )();
+    }
+
+    options.server = {
+      type:
+        // eslint-disable-next-line no-nested-ternary
+        typeof options.server === "string"
+          ? options.server
+          : // eslint-disable-next-line no-nested-ternary
+          typeof (options.server || {}).type === "string"
+          ? /** @type {ServerConfiguration} */ (options.server).type || "http"
+          : // eslint-disable-next-line no-nested-ternary
+          isSPDY
+          ? "spdy"
+          : isHTTPs
+          ? "https"
+          : "http",
+      options: {
+        .../** @type {ServerOptions} */ (options.https),
+        .../** @type {ServerConfiguration} */ (options.server || {}).options,
+      },
+    };
+
+    if (
+      options.server.type === "spdy" &&
+      typeof (/** @type {ServerOptions} */ (options.server.options).spdy) ===
+        "undefined"
+    ) {
+      /** @type {ServerOptions} */
+      (options.server.options).spdy = {
+        protocols: ["h2", "http/1.1"],
+      };
+    }
+
+    if (options.server.type === "https" || options.server.type === "spdy") {
+      if (
+        typeof (
+          /** @type {ServerOptions} */ (options.server.options).requestCert
+        ) === "undefined"
+      ) {
+        /** @type {ServerOptions} */
+        (options.server.options).requestCert = false;
+      }
+
+      const httpsProperties =
+        /** @type {Array<keyof ServerOptions>} */
+        (["cacert", "ca", "cert", "crl", "key", "pfx"]);
+
+      for (const property of httpsProperties) {
+        if (
+          typeof (
+            /** @type {ServerOptions} */ (options.server.options)[property]
+          ) === "undefined"
+        ) {
+          // eslint-disable-next-line no-continue
+          continue;
+        }
+
+        // @ts-ignore
+        if (property === "cacert") {
+          // TODO remove the `cacert` option in favor `ca` in the next major release
+          util.deprecate(
+            () => {},
+            "The 'cacert' option is deprecated. Please use the 'ca' option.",
+            "DEP_WEBPACK_DEV_SERVER_CACERT"
+          )();
+        }
+
+        /** @type {any} */
+        const value =
+          /** @type {ServerOptions} */
+          (options.server.options)[property];
+        /**
+         * @param {string | Buffer | undefined} item
+         * @returns {string | Buffer | undefined}
+         */
+        const readFile = (item) => {
+          if (
+            Buffer.isBuffer(item) ||
+            (typeof item === "object" && item !== null && !Array.isArray(item))
+          ) {
+            return item;
+          }
+
+          if (item) {
+            let stats = null;
+
+            try {
+              stats = fs.lstatSync(fs.realpathSync(item)).isFile();
+            } catch (error) {
+              // Ignore error
+            }
+
+            // It is a file
+            return stats ? fs.readFileSync(item) : item;
+          }
+        };
+
+        /** @type {any} */
+        (options.server.options)[property] = Array.isArray(value)
+          ? value.map((item) => readFile(item))
+          : readFile(value);
+      }
+
+      let fakeCert;
+
+      if (
+        !(/** @type {ServerOptions} */ (options.server.options).key) ||
+        !(/** @type {ServerOptions} */ (options.server.options).cert)
+      ) {
+        const certificateDir = Server.findCacheDir();
+        const certificatePath = path.join(certificateDir, "server.pem");
+        let certificateExists;
+
+        try {
+          const certificate = await fs.promises.stat(certificatePath);
+          certificateExists = certificate.isFile();
+        } catch {
+          certificateExists = false;
+        }
+
+        if (certificateExists) {
+          const certificateTtl = 1000 * 60 * 60 * 24;
+          const certificateStat = await fs.promises.stat(certificatePath);
+          const now = Number(new Date());
+
+          // cert is more than 30 days old, kill it with fire
+          if ((now - Number(certificateStat.ctime)) / certificateTtl > 30) {
+            const { promisify } = require("util");
+            const rimraf = require("rimraf");
+            const del = promisify(rimraf);
+
+            this.logger.info(
+              "SSL certificate is more than 30 days old. Removing..."
+            );
+
+            await del(certificatePath);
+
+            certificateExists = false;
+          }
+        }
+
+        if (!certificateExists) {
+          this.logger.info("Generating SSL certificate...");
+
+          // @ts-ignore
+          const selfsigned = require("selfsigned");
+          const attributes = [{ name: "commonName", value: "localhost" }];
+          const pems = selfsigned.generate(attributes, {
+            algorithm: "sha256",
+            days: 30,
+            keySize: 2048,
+            extensions: [
+              {
+                name: "basicConstraints",
+                cA: true,
+              },
+              {
+                name: "keyUsage",
+                keyCertSign: true,
+                digitalSignature: true,
+                nonRepudiation: true,
+                keyEncipherment: true,
+                dataEncipherment: true,
+              },
+              {
+                name: "extKeyUsage",
+                serverAuth: true,
+                clientAuth: true,
+                codeSigning: true,
+                timeStamping: true,
+              },
+              {
+                name: "subjectAltName",
+                altNames: [
+                  {
+                    // type 2 is DNS
+                    type: 2,
+                    value: "localhost",
+                  },
+                  {
+                    type: 2,
+                    value: "localhost.localdomain",
+                  },
+                  {
+                    type: 2,
+                    value: "lvh.me",
+                  },
+                  {
+                    type: 2,
+                    value: "*.lvh.me",
+                  },
+                  {
+                    type: 2,
+                    value: "[::1]",
+                  },
+                  {
+                    // type 7 is IP
+                    type: 7,
+                    ip: "127.0.0.1",
+                  },
+                  {
+                    type: 7,
+                    ip: "fe80::1",
+                  },
+                ],
+              },
+            ],
+          });
+
+          await fs.promises.mkdir(certificateDir, { recursive: true });
+
+          await fs.promises.writeFile(
+            certificatePath,
+            pems.private + pems.cert,
+            {
+              encoding: "utf8",
+            }
+          );
+        }
+
+        fakeCert = await fs.promises.readFile(certificatePath);
+
+        this.logger.info(`SSL certificate: ${certificatePath}`);
+      }
+
+      if (
+        /** @type {ServerOptions & { cacert?: ServerOptions["ca"] }} */ (
+          options.server.options
+        ).cacert
+      ) {
+        if (/** @type {ServerOptions} */ (options.server.options).ca) {
+          this.logger.warn(
+            "Do not specify 'ca' and 'cacert' options together, the 'ca' option will be used."
+          );
+        } else {
+          /** @type {ServerOptions} */
+          (options.server.options).ca =
+            /** @type {ServerOptions & { cacert?: ServerOptions["ca"] }} */
+            (options.server.options).cacert;
+        }
+
+        delete (
+          /** @type {ServerOptions & { cacert?: ServerOptions["ca"] }} */ (
+            options.server.options
+          ).cacert
+        );
+      }
+
+      /** @type {ServerOptions} */
+      (options.server.options).key =
+        /** @type {ServerOptions} */
+        (options.server.options).key || fakeCert;
+      /** @type {ServerOptions} */
+      (options.server.options).cert =
+        /** @type {ServerOptions} */
+        (options.server.options).cert || fakeCert;
+    }
+
+    if (typeof options.ipc === "boolean") {
+      const isWindows = process.platform === "win32";
+      const pipePrefix = isWindows ? "\\\\.\\pipe\\" : os.tmpdir();
+      const pipeName = "webpack-dev-server.sock";
+
+      options.ipc = path.join(pipePrefix, pipeName);
+    }
+
+    options.liveReload =
+      typeof options.liveReload !== "undefined" ? options.liveReload : true;
+
+    options.magicHtml =
+      typeof options.magicHtml !== "undefined" ? options.magicHtml : true;
+
+    // https://github.com/webpack/webpack-dev-server/issues/1990
+    const defaultOpenOptions = { wait: false };
+    /**
+     * @param {any} target
+     * @returns {NormalizedOpen[]}
+     */
+    // TODO: remove --open-app in favor of --open-app-name
+    const getOpenItemsFromObject = ({ target, ...rest }) => {
+      const normalizedOptions = { ...defaultOpenOptions, ...rest };
+
+      if (typeof normalizedOptions.app === "string") {
+        normalizedOptions.app = {
+          name: normalizedOptions.app,
+        };
+      }
+
+      const normalizedTarget = typeof target === "undefined" ? "<url>" : target;
+
+      if (Array.isArray(normalizedTarget)) {
+        return normalizedTarget.map((singleTarget) => {
+          return { target: singleTarget, options: normalizedOptions };
+        });
+      }
+
+      return [{ target: normalizedTarget, options: normalizedOptions }];
+    };
+
+    if (typeof options.open === "undefined") {
+      /** @type {NormalizedOpen[]} */
+      (options.open) = [];
+    } else if (typeof options.open === "boolean") {
+      /** @type {NormalizedOpen[]} */
+      (options.open) = options.open
+        ? [
+            {
+              target: "<url>",
+              options: /** @type {OpenOptions} */ (defaultOpenOptions),
+            },
+          ]
+        : [];
+    } else if (typeof options.open === "string") {
+      /** @type {NormalizedOpen[]} */
+      (options.open) = [{ target: options.open, options: defaultOpenOptions }];
+    } else if (Array.isArray(options.open)) {
+      /**
+       * @type {NormalizedOpen[]}
+       */
+      const result = [];
+
+      options.open.forEach((item) => {
+        if (typeof item === "string") {
+          result.push({ target: item, options: defaultOpenOptions });
+
+          return;
+        }
+
+        result.push(...getOpenItemsFromObject(item));
+      });
+
+      /** @type {NormalizedOpen[]} */
+      (options.open) = result;
+    } else {
+      /** @type {NormalizedOpen[]} */
+      (options.open) = [...getOpenItemsFromObject(options.open)];
+    }
+
+    if (options.onAfterSetupMiddleware) {
+      // TODO: remove in the next major release
+      util.deprecate(
+        () => {},
+        "'onAfterSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.",
+        `DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE`
+      )();
+    }
+
+    if (options.onBeforeSetupMiddleware) {
+      // TODO: remove in the next major release
+      util.deprecate(
+        () => {},
+        "'onBeforeSetupMiddleware' option is deprecated. Please use the 'setupMiddlewares' option.",
+        `DEP_WEBPACK_DEV_SERVER_ON_BEFORE_SETUP_MIDDLEWARE`
+      )();
+    }
+
+    if (typeof options.port === "string" && options.port !== "auto") {
+      options.port = Number(options.port);
+    }
+
+    /**
+     * Assume a proxy configuration specified as:
+     * proxy: {
+     *   'context': { options }
+     * }
+     * OR
+     * proxy: {
+     *   'context': 'target'
+     * }
+     */
+    if (typeof options.proxy !== "undefined") {
+      // TODO remove in the next major release, only accept `Array`
+      if (!Array.isArray(options.proxy)) {
+        if (
+          Object.prototype.hasOwnProperty.call(options.proxy, "target") ||
+          Object.prototype.hasOwnProperty.call(options.proxy, "router")
+        ) {
+          /** @type {ProxyConfigArray} */
+          (options.proxy) = [/** @type {ProxyConfigMap} */ (options.proxy)];
+        } else {
+          /** @type {ProxyConfigArray} */
+          (options.proxy) = Object.keys(options.proxy).map(
+            /**
+             * @param {string} context
+             * @returns {HttpProxyMiddlewareOptions}
+             */
+            (context) => {
+              let proxyOptions;
+              // For backwards compatibility reasons.
+              const correctedContext = context
+                .replace(/^\*$/, "**")
+                .replace(/\/\*$/, "");
+
+              if (
+                typeof (
+                  /** @type {ProxyConfigMap} */ (options.proxy)[context]
+                ) === "string"
+              ) {
+                proxyOptions = {
+                  context: correctedContext,
+                  target:
+                    /** @type {ProxyConfigMap} */
+                    (options.proxy)[context],
+                };
+              } else {
+                proxyOptions = {
+                  // @ts-ignore
+                  .../** @type {ProxyConfigMap} */ (options.proxy)[context],
+                };
+                proxyOptions.context = correctedContext;
+              }
+
+              return proxyOptions;
+            }
+          );
+        }
+      }
+
+      /** @type {ProxyConfigArray} */
+      (options.proxy) =
+        /** @type {ProxyConfigArray} */
+        (options.proxy).map((item) => {
+          if (typeof item === "function") {
+            return item;
+          }
+
+          /**
+           * @param {"info" | "warn" | "error" | "debug" | "silent" | undefined | "none" | "log" | "verbose"} level
+           * @returns {"info" | "warn" | "error" | "debug" | "silent" | undefined}
+           */
+          const getLogLevelForProxy = (level) => {
+            if (level === "none") {
+              return "silent";
+            }
+
+            if (level === "log") {
+              return "info";
+            }
+
+            if (level === "verbose") {
+              return "debug";
+            }
+
+            return level;
+          };
+
+          if (typeof item.logLevel === "undefined") {
+            item.logLevel = getLogLevelForProxy(
+              compilerOptions.infrastructureLogging
+                ? compilerOptions.infrastructureLogging.level
+                : "info"
+            );
+          }
+
+          if (typeof item.logProvider === "undefined") {
+            item.logProvider = () => this.logger;
+          }
+
+          return item;
+        });
+    }
+
+    if (typeof options.setupExitSignals === "undefined") {
+      options.setupExitSignals = true;
+    }
+
+    if (typeof options.static === "undefined") {
+      options.static = [getStaticItem()];
+    } else if (typeof options.static === "boolean") {
+      options.static = options.static ? [getStaticItem()] : false;
+    } else if (typeof options.static === "string") {
+      options.static = [getStaticItem(options.static)];
+    } else if (Array.isArray(options.static)) {
+      options.static = options.static.map((item) => getStaticItem(item));
+    } else {
+      options.static = [getStaticItem(options.static)];
+    }
+
+    if (typeof options.watchFiles === "string") {
+      options.watchFiles = [
+        { paths: options.watchFiles, options: getWatchOptions() },
+      ];
+    } else if (
+      typeof options.watchFiles === "object" &&
+      options.watchFiles !== null &&
+      !Array.isArray(options.watchFiles)
+    ) {
+      options.watchFiles = [
+        {
+          paths: options.watchFiles.paths,
+          options: getWatchOptions(options.watchFiles.options || {}),
+        },
+      ];
+    } else if (Array.isArray(options.watchFiles)) {
+      options.watchFiles = options.watchFiles.map((item) => {
+        if (typeof item === "string") {
+          return { paths: item, options: getWatchOptions() };
+        }
+
+        return {
+          paths: item.paths,
+          options: getWatchOptions(item.options || {}),
+        };
+      });
+    } else {
+      options.watchFiles = [];
+    }
+
+    const defaultWebSocketServerType = "ws";
+    const defaultWebSocketServerOptions = { path: "/ws" };
+
+    if (typeof options.webSocketServer === "undefined") {
+      options.webSocketServer = {
+        type: defaultWebSocketServerType,
+        options: defaultWebSocketServerOptions,
+      };
+    } else if (
+      typeof options.webSocketServer === "boolean" &&
+      !options.webSocketServer
+    ) {
+      options.webSocketServer = false;
+    } else if (
+      typeof options.webSocketServer === "string" ||
+      typeof options.webSocketServer === "function"
+    ) {
+      options.webSocketServer = {
+        type: options.webSocketServer,
+        options: defaultWebSocketServerOptions,
+      };
+    } else {
+      options.webSocketServer = {
+        type:
+          /** @type {WebSocketServerConfiguration} */
+          (options.webSocketServer).type || defaultWebSocketServerType,
+        options: {
+          ...defaultWebSocketServerOptions,
+          .../** @type {WebSocketServerConfiguration} */
+          (options.webSocketServer).options,
+        },
+      };
+
+      const webSocketServer =
+        /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable<WebSocketServerConfiguration["options"]> }} */
+        (options.webSocketServer);
+
+      if (typeof webSocketServer.options.port === "string") {
+        webSocketServer.options.port = Number(webSocketServer.options.port);
+      }
+    }
+  }
+
+  /**
+   * @private
+   * @returns {string}
+   */
+  getClientTransport() {
+    let clientImplementation;
+    let clientImplementationFound = true;
+
+    const isKnownWebSocketServerImplementation =
+      this.options.webSocketServer &&
+      typeof (
+        /** @type {WebSocketServerConfiguration} */
+        (this.options.webSocketServer).type
+      ) === "string" &&
+      // @ts-ignore
+      (this.options.webSocketServer.type === "ws" ||
+        /** @type {WebSocketServerConfiguration} */
+        (this.options.webSocketServer).type === "sockjs");
+
+    let clientTransport;
+
+    if (this.options.client) {
+      if (
+        typeof (
+          /** @type {ClientConfiguration} */
+          (this.options.client).webSocketTransport
+        ) !== "undefined"
+      ) {
+        clientTransport =
+          /** @type {ClientConfiguration} */
+          (this.options.client).webSocketTransport;
+      } else if (isKnownWebSocketServerImplementation) {
+        clientTransport =
+          /** @type {WebSocketServerConfiguration} */
+          (this.options.webSocketServer).type;
+      } else {
+        clientTransport = "ws";
+      }
+    } else {
+      clientTransport = "ws";
+    }
+
+    switch (typeof clientTransport) {
+      case "string":
+        // could be 'sockjs', 'ws', or a path that should be required
+        if (clientTransport === "sockjs") {
+          clientImplementation = require.resolve(
+            "../client/clients/SockJSClient"
+          );
+        } else if (clientTransport === "ws") {
+          clientImplementation = require.resolve(
+            "../client/clients/WebSocketClient"
+          );
+        } else {
+          try {
+            clientImplementation = require.resolve(clientTransport);
+          } catch (e) {
+            clientImplementationFound = false;
+          }
+        }
+        break;
+      default:
+        clientImplementationFound = false;
+    }
+
+    if (!clientImplementationFound) {
+      throw new Error(
+        `${
+          !isKnownWebSocketServerImplementation
+            ? "When you use custom web socket implementation you must explicitly specify client.webSocketTransport. "
+            : ""
+        }client.webSocketTransport must be a string denoting a default implementation (e.g. 'sockjs', 'ws') or a full path to a JS file via require.resolve(...) which exports a class `
+      );
+    }
+
+    return /** @type {string} */ (clientImplementation);
+  }
+
+  /**
+   * @private
+   * @returns {string}
+   */
+  getServerTransport() {
+    let implementation;
+    let implementationFound = true;
+
+    switch (
+      typeof (
+        /** @type {WebSocketServerConfiguration} */
+        (this.options.webSocketServer).type
+      )
+    ) {
+      case "string":
+        // Could be 'sockjs', in the future 'ws', or a path that should be required
+        if (
+          /** @type {WebSocketServerConfiguration} */ (
+            this.options.webSocketServer
+          ).type === "sockjs"
+        ) {
+          implementation = require("./servers/SockJSServer");
+        } else if (
+          /** @type {WebSocketServerConfiguration} */ (
+            this.options.webSocketServer
+          ).type === "ws"
+        ) {
+          implementation = require("./servers/WebsocketServer");
+        } else {
+          try {
+            // eslint-disable-next-line import/no-dynamic-require
+            implementation = require(/** @type {WebSocketServerConfiguration} */ (
+              this.options.webSocketServer
+            ).type);
+          } catch (error) {
+            implementationFound = false;
+          }
+        }
+        break;
+      case "function":
+        implementation = /** @type {WebSocketServerConfiguration} */ (
+          this.options.webSocketServer
+        ).type;
+        break;
+      default:
+        implementationFound = false;
+    }
+
+    if (!implementationFound) {
+      throw new Error(
+        "webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to " +
+          "a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) " +
+          "via require.resolve(...), or the class itself which extends BaseServer"
+      );
+    }
+
+    return implementation;
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupProgressPlugin() {
+    const { ProgressPlugin } =
+      /** @type {MultiCompiler}*/
+      (this.compiler).compilers
+        ? /** @type {MultiCompiler}*/ (this.compiler).compilers[0].webpack
+        : /** @type {Compiler}*/ (this.compiler).webpack ||
+          // TODO remove me after drop webpack v4
+          require("webpack");
+
+    new ProgressPlugin(
+      /**
+       * @param {number} percent
+       * @param {string} msg
+       * @param {string} addInfo
+       * @param {string} pluginName
+       */
+      (percent, msg, addInfo, pluginName) => {
+        percent = Math.floor(percent * 100);
+
+        if (percent === 100) {
+          msg = "Compilation completed";
+        }
+
+        if (addInfo) {
+          msg = `${msg} (${addInfo})`;
+        }
+
+        if (this.webSocketServer) {
+          this.sendMessage(this.webSocketServer.clients, "progress-update", {
+            percent,
+            msg,
+            pluginName,
+          });
+        }
+
+        if (this.server) {
+          this.server.emit("progress-update", { percent, msg, pluginName });
+        }
+      }
+    ).apply(this.compiler);
+  }
+
+  /**
+   * @private
+   * @returns {Promise<void>}
+   */
+  async initialize() {
+    if (this.options.webSocketServer) {
+      const compilers =
+        /** @type {MultiCompiler} */
+        (this.compiler).compilers || [this.compiler];
+
+      compilers.forEach((compiler) => {
+        this.addAdditionalEntries(compiler);
+
+        const webpack = compiler.webpack || require("webpack");
+
+        new webpack.ProvidePlugin({
+          __webpack_dev_server_client__: this.getClientTransport(),
+        }).apply(compiler);
+
+        // TODO remove after drop webpack v4 support
+        compiler.options.plugins = compiler.options.plugins || [];
+
+        if (this.options.hot) {
+          const HMRPluginExists = compiler.options.plugins.find(
+            (p) => p.constructor === webpack.HotModuleReplacementPlugin
+          );
+
+          if (HMRPluginExists) {
+            this.logger.warn(
+              `"hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.`
+            );
+          } else {
+            // Apply the HMR plugin
+            const plugin = new webpack.HotModuleReplacementPlugin();
+
+            plugin.apply(compiler);
+          }
+        }
+      });
+
+      if (
+        this.options.client &&
+        /** @type {ClientConfiguration} */ (this.options.client).progress
+      ) {
+        this.setupProgressPlugin();
+      }
+    }
+
+    this.setupHooks();
+    this.setupApp();
+    this.setupHostHeaderCheck();
+    this.setupDevMiddleware();
+    // Should be after `webpack-dev-middleware`, otherwise other middlewares might rewrite response
+    this.setupBuiltInRoutes();
+    this.setupWatchFiles();
+    this.setupWatchStaticFiles();
+    this.setupMiddlewares();
+    this.createServer();
+
+    if (this.options.setupExitSignals) {
+      const signals = ["SIGINT", "SIGTERM"];
+
+      let needForceShutdown = false;
+
+      signals.forEach((signal) => {
+        const listener = () => {
+          if (needForceShutdown) {
+            process.exit();
+          }
+
+          this.logger.info(
+            "Gracefully shutting down. To force exit, press ^C again. Please wait..."
+          );
+
+          needForceShutdown = true;
+
+          this.stopCallback(() => {
+            if (typeof this.compiler.close === "function") {
+              this.compiler.close(() => {
+                process.exit();
+              });
+            } else {
+              process.exit();
+            }
+          });
+        };
+
+        this.listeners.push({ name: signal, listener });
+
+        process.on(signal, listener);
+      });
+    }
+
+    // Proxy WebSocket without the initial http request
+    // https://github.com/chimurai/http-proxy-middleware#external-websocket-upgrade
+    /** @type {RequestHandler[]} */
+    (this.webSocketProxies).forEach((webSocketProxy) => {
+      /** @type {import("http").Server} */
+      (this.server).on(
+        "upgrade",
+        /** @type {RequestHandler & { upgrade: NonNullable<RequestHandler["upgrade"]> }} */
+        (webSocketProxy).upgrade
+      );
+    }, this);
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupApp() {
+    /** @type {import("express").Application | undefined}*/
+    this.app = new /** @type {any} */ (getExpress())();
+  }
+
+  /**
+   * @private
+   * @param {Stats | MultiStats} statsObj
+   * @returns {StatsCompilation}
+   */
+  getStats(statsObj) {
+    const stats = Server.DEFAULT_STATS;
+    const compilerOptions = this.getCompilerOptions();
+
+    // @ts-ignore
+    if (compilerOptions.stats && compilerOptions.stats.warningsFilter) {
+      // @ts-ignore
+      stats.warningsFilter = compilerOptions.stats.warningsFilter;
+    }
+
+    return statsObj.toJson(stats);
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupHooks() {
+    this.compiler.hooks.invalid.tap("webpack-dev-server", () => {
+      if (this.webSocketServer) {
+        this.sendMessage(this.webSocketServer.clients, "invalid");
+      }
+    });
+    this.compiler.hooks.done.tap(
+      "webpack-dev-server",
+      /**
+       * @param {Stats | MultiStats} stats
+       */
+      (stats) => {
+        if (this.webSocketServer) {
+          this.sendStats(this.webSocketServer.clients, this.getStats(stats));
+        }
+
+        /**
+         * @private
+         * @type {Stats | MultiStats}
+         */
+        this.stats = stats;
+      }
+    );
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupHostHeaderCheck() {
+    /** @type {import("express").Application} */
+    (this.app).all(
+      "*",
+      /**
+       * @param {Request} req
+       * @param {Response} res
+       * @param {NextFunction} next
+       * @returns {void}
+       */
+      (req, res, next) => {
+        if (
+          this.checkHeader(
+            /** @type {{ [key: string]: string | undefined }} */
+            (req.headers),
+            "host"
+          )
+        ) {
+          return next();
+        }
+
+        res.send("Invalid Host header");
+      }
+    );
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupDevMiddleware() {
+    const webpackDevMiddleware = require("webpack-dev-middleware");
+
+    // middleware for serving webpack bundle
+    this.middleware = webpackDevMiddleware(
+      this.compiler,
+      this.options.devMiddleware
+    );
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupBuiltInRoutes() {
+    const { app, middleware } = this;
+
+    /** @type {import("express").Application} */
+    (app).get(
+      "/__webpack_dev_server__/sockjs.bundle.js",
+      /**
+       * @param {Request} req
+       * @param {Response} res
+       * @returns {void}
+       */
+      (req, res) => {
+        res.setHeader("Content-Type", "application/javascript");
+
+        const clientPath = path.join(__dirname, "..", "client");
+
+        res.sendFile(path.join(clientPath, "modules/sockjs-client/index.js"));
+      }
+    );
+
+    /** @type {import("express").Application} */
+    (app).get(
+      "/webpack-dev-server/invalidate",
+      /**
+       * @param {Request} _req
+       * @param {Response} res
+       * @returns {void}
+       */
+      (_req, res) => {
+        this.invalidate();
+
+        res.end();
+      }
+    );
+
+    /** @type {import("express").Application} */
+    (app).get("/webpack-dev-server/open-editor", (req, res) => {
+      const fileName = req.query.fileName;
+
+      if (typeof fileName === "string") {
+        // @ts-ignore
+        const launchEditor = require("launch-editor");
+        launchEditor(fileName);
+      }
+
+      res.end();
+    });
+
+    /** @type {import("express").Application} */
+    (app).get(
+      "/webpack-dev-server",
+      /**
+       * @param {Request} req
+       * @param {Response} res
+       * @returns {void}
+       */
+      (req, res) => {
+        /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
+        (middleware).waitUntilValid((stats) => {
+          res.setHeader("Content-Type", "text/html");
+          res.write(
+            '<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body>'
+          );
+
+          const statsForPrint =
+            typeof (/** @type {MultiStats} */ (stats).stats) !== "undefined"
+              ? /** @type {MultiStats} */ (stats).toJson().children
+              : [/** @type {Stats} */ (stats).toJson()];
+
+          res.write(`<h1>Assets Report:</h1>`);
+
+          /**
+           * @type {StatsCompilation[]}
+           */
+          (statsForPrint).forEach((item, index) => {
+            res.write("<div>");
+
+            const name =
+              // eslint-disable-next-line no-nested-ternary
+              typeof item.name !== "undefined"
+                ? item.name
+                : /** @type {MultiStats} */ (stats).stats
+                ? `unnamed[${index}]`
+                : "unnamed";
+
+            res.write(`<h2>Compilation: ${name}</h2>`);
+            res.write("<ul>");
+
+            const publicPath =
+              item.publicPath === "auto" ? "" : item.publicPath;
+
+            for (const asset of /** @type {NonNullable<StatsCompilation["assets"]>} */ (
+              item.assets
+            )) {
+              const assetName = asset.name;
+              const assetURL = `${publicPath}${assetName}`;
+
+              res.write(
+                `<li>
+              <strong><a href="${assetURL}" target="_blank">${assetName}</a></strong>
+            </li>`
+              );
+            }
+
+            res.write("</ul>");
+            res.write("</div>");
+          });
+
+          res.end("</body></html>");
+        });
+      }
+    );
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupWatchStaticFiles() {
+    if (/** @type {NormalizedStatic[]} */ (this.options.static).length > 0) {
+      /** @type {NormalizedStatic[]} */
+      (this.options.static).forEach((staticOption) => {
+        if (staticOption.watch) {
+          this.watchFiles(staticOption.directory, staticOption.watch);
+        }
+      });
+    }
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupWatchFiles() {
+    const { watchFiles } = this.options;
+
+    if (/** @type {WatchFiles[]} */ (watchFiles).length > 0) {
+      /** @type {WatchFiles[]} */
+      (watchFiles).forEach((item) => {
+        this.watchFiles(item.paths, item.options);
+      });
+    }
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  setupMiddlewares() {
+    /**
+     * @type {Array<Middleware>}
+     */
+    let middlewares = [];
+
+    // compress is placed last and uses unshift so that it will be the first middleware used
+    if (this.options.compress) {
+      const compression = require("compression");
+
+      middlewares.push({ name: "compression", middleware: compression() });
+    }
+
+    if (typeof this.options.onBeforeSetupMiddleware === "function") {
+      this.options.onBeforeSetupMiddleware(this);
+    }
+
+    if (typeof this.options.headers !== "undefined") {
+      middlewares.push({
+        name: "set-headers",
+        path: "*",
+        middleware: this.setHeaders.bind(this),
+      });
+    }
+
+    middlewares.push({
+      name: "webpack-dev-middleware",
+      middleware:
+        /** @type {import("webpack-dev-middleware").Middleware<Request, Response>}*/
+        (this.middleware),
+    });
+
+    if (this.options.proxy) {
+      const { createProxyMiddleware } = require("http-proxy-middleware");
+
+      /**
+       * @param {ProxyConfigArrayItem} proxyConfig
+       * @returns {RequestHandler | undefined}
+       */
+      const getProxyMiddleware = (proxyConfig) => {
+        // It is possible to use the `bypass` method without a `target` or `router`.
+        // However, the proxy middleware has no use in this case, and will fail to instantiate.
+        if (proxyConfig.target) {
+          const context = proxyConfig.context || proxyConfig.path;
+
+          return createProxyMiddleware(
+            /** @type {string} */ (context),
+            proxyConfig
+          );
+        }
+
+        if (proxyConfig.router) {
+          return createProxyMiddleware(proxyConfig);
+        }
+      };
+
+      /**
+       * Assume a proxy configuration specified as:
+       * proxy: [
+       *   {
+       *     context: "value",
+       *     ...options,
+       *   },
+       *   // or:
+       *   function() {
+       *     return {
+       *       context: "context",
+       *       ...options,
+       *     };
+       *   }
+       * ]
+       */
+      /** @type {ProxyConfigArray} */
+      (this.options.proxy).forEach((proxyConfigOrCallback) => {
+        /**
+         * @type {RequestHandler}
+         */
+        let proxyMiddleware;
+
+        let proxyConfig =
+          typeof proxyConfigOrCallback === "function"
+            ? proxyConfigOrCallback()
+            : proxyConfigOrCallback;
+
+        proxyMiddleware =
+          /** @type {RequestHandler} */
+          (getProxyMiddleware(proxyConfig));
+
+        if (proxyConfig.ws) {
+          this.webSocketProxies.push(proxyMiddleware);
+        }
+
+        /**
+         * @param {Request} req
+         * @param {Response} res
+         * @param {NextFunction} next
+         * @returns {Promise<void>}
+         */
+        const handler = async (req, res, next) => {
+          if (typeof proxyConfigOrCallback === "function") {
+            const newProxyConfig = proxyConfigOrCallback(req, res, next);
+
+            if (newProxyConfig !== proxyConfig) {
+              proxyConfig = newProxyConfig;
+              proxyMiddleware =
+                /** @type {RequestHandler} */
+                (getProxyMiddleware(proxyConfig));
+            }
+          }
+
+          // - Check if we have a bypass function defined
+          // - In case the bypass function is defined we'll retrieve the
+          // bypassUrl from it otherwise bypassUrl would be null
+          // TODO remove in the next major in favor `context` and `router` options
+          const isByPassFuncDefined = typeof proxyConfig.bypass === "function";
+          const bypassUrl = isByPassFuncDefined
+            ? await /** @type {ByPass} */ (proxyConfig.bypass)(
+                req,
+                res,
+                proxyConfig
+              )
+            : null;
+
+          if (typeof bypassUrl === "boolean") {
+            // skip the proxy
+            // @ts-ignore
+            req.url = null;
+            next();
+          } else if (typeof bypassUrl === "string") {
+            // byPass to that url
+            req.url = bypassUrl;
+            next();
+          } else if (proxyMiddleware) {
+            return proxyMiddleware(req, res, next);
+          } else {
+            next();
+          }
+        };
+
+        middlewares.push({
+          name: "http-proxy-middleware",
+          middleware: handler,
+        });
+        // Also forward error requests to the proxy so it can handle them.
+        middlewares.push({
+          name: "http-proxy-middleware-error-handler",
+          middleware:
+            /**
+             * @param {Error} error
+             * @param {Request} req
+             * @param {Response} res
+             * @param {NextFunction} next
+             * @returns {any}
+             */
+            (error, req, res, next) => handler(req, res, next),
+        });
+      });
+
+      middlewares.push({
+        name: "webpack-dev-middleware",
+        middleware:
+          /** @type {import("webpack-dev-middleware").Middleware<Request, Response>}*/
+          (this.middleware),
+      });
+    }
+
+    if (/** @type {NormalizedStatic[]} */ (this.options.static).length > 0) {
+      /** @type {NormalizedStatic[]} */
+      (this.options.static).forEach((staticOption) => {
+        staticOption.publicPath.forEach((publicPath) => {
+          middlewares.push({
+            name: "express-static",
+            path: publicPath,
+            middleware: getExpress().static(
+              staticOption.directory,
+              staticOption.staticOptions
+            ),
+          });
+        });
+      });
+    }
+
+    if (this.options.historyApiFallback) {
+      const connectHistoryApiFallback = require("connect-history-api-fallback");
+      const { historyApiFallback } = this.options;
+
+      if (
+        typeof (
+          /** @type {ConnectHistoryApiFallbackOptions} */
+          (historyApiFallback).logger
+        ) === "undefined" &&
+        !(
+          /** @type {ConnectHistoryApiFallbackOptions} */
+          (historyApiFallback).verbose
+        )
+      ) {
+        // @ts-ignore
+        historyApiFallback.logger = this.logger.log.bind(
+          this.logger,
+          "[connect-history-api-fallback]"
+        );
+      }
+
+      // Fall back to /index.html if nothing else matches.
+      middlewares.push({
+        name: "connect-history-api-fallback",
+        middleware: connectHistoryApiFallback(
+          /** @type {ConnectHistoryApiFallbackOptions} */
+          (historyApiFallback)
+        ),
+      });
+
+      // include our middleware to ensure
+      // it is able to handle '/index.html' request after redirect
+      middlewares.push({
+        name: "webpack-dev-middleware",
+        middleware:
+          /** @type {import("webpack-dev-middleware").Middleware<Request, Response>}*/
+          (this.middleware),
+      });
+
+      if (/** @type {NormalizedStatic[]} */ (this.options.static).length > 0) {
+        /** @type {NormalizedStatic[]} */
+        (this.options.static).forEach((staticOption) => {
+          staticOption.publicPath.forEach((publicPath) => {
+            middlewares.push({
+              name: "express-static",
+              path: publicPath,
+              middleware: getExpress().static(
+                staticOption.directory,
+                staticOption.staticOptions
+              ),
+            });
+          });
+        });
+      }
+    }
+
+    if (/** @type {NormalizedStatic[]} */ (this.options.static).length > 0) {
+      const serveIndex = require("serve-index");
+
+      /** @type {NormalizedStatic[]} */
+      (this.options.static).forEach((staticOption) => {
+        staticOption.publicPath.forEach((publicPath) => {
+          if (staticOption.serveIndex) {
+            middlewares.push({
+              name: "serve-index",
+              path: publicPath,
+              /**
+               * @param {Request} req
+               * @param {Response} res
+               * @param {NextFunction} next
+               * @returns {void}
+               */
+              middleware: (req, res, next) => {
+                // serve-index doesn't fallthrough non-get/head request to next middleware
+                if (req.method !== "GET" && req.method !== "HEAD") {
+                  return next();
+                }
+
+                serveIndex(
+                  staticOption.directory,
+                  /** @type {ServeIndexOptions} */
+                  (staticOption.serveIndex)
+                )(req, res, next);
+              },
+            });
+          }
+        });
+      });
+    }
+
+    if (this.options.magicHtml) {
+      middlewares.push({
+        name: "serve-magic-html",
+        middleware: this.serveMagicHtml.bind(this),
+      });
+    }
+
+    // Register this middleware always as the last one so that it's only used as a
+    // fallback when no other middleware responses.
+    middlewares.push({
+      name: "options-middleware",
+      path: "*",
+      /**
+       * @param {Request} req
+       * @param {Response} res
+       * @param {NextFunction} next
+       * @returns {void}
+       */
+      middleware: (req, res, next) => {
+        if (req.method === "OPTIONS") {
+          res.statusCode = 204;
+          res.setHeader("Content-Length", "0");
+          res.end();
+          return;
+        }
+        next();
+      },
+    });
+
+    if (typeof this.options.setupMiddlewares === "function") {
+      middlewares = this.options.setupMiddlewares(middlewares, this);
+    }
+
+    middlewares.forEach((middleware) => {
+      if (typeof middleware === "function") {
+        /** @type {import("express").Application} */
+        (this.app).use(middleware);
+      } else if (typeof middleware.path !== "undefined") {
+        /** @type {import("express").Application} */
+        (this.app).use(middleware.path, middleware.middleware);
+      } else {
+        /** @type {import("express").Application} */
+        (this.app).use(middleware.middleware);
+      }
+    });
+
+    if (typeof this.options.onAfterSetupMiddleware === "function") {
+      this.options.onAfterSetupMiddleware(this);
+    }
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  createServer() {
+    const { type, options } = /** @type {ServerConfiguration} */ (
+      this.options.server
+    );
+
+    /** @type {import("http").Server | undefined | null} */
+    // eslint-disable-next-line import/no-dynamic-require
+    this.server = require(/** @type {string} */ (type)).createServer(
+      options,
+      this.app
+    );
+
+    /** @type {import("http").Server} */
+    (this.server).on(
+      "connection",
+      /**
+       * @param {Socket} socket
+       */
+      (socket) => {
+        // Add socket to list
+        this.sockets.push(socket);
+
+        socket.once("close", () => {
+          // Remove socket from list
+          this.sockets.splice(this.sockets.indexOf(socket), 1);
+        });
+      }
+    );
+
+    /** @type {import("http").Server} */
+    (this.server).on(
+      "error",
+      /**
+       * @param {Error} error
+       */
+      (error) => {
+        throw error;
+      }
+    );
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  // TODO: remove `--web-socket-server` in favor of `--web-socket-server-type`
+  createWebSocketServer() {
+    /** @type {WebSocketServerImplementation | undefined | null} */
+    this.webSocketServer = new /** @type {any} */ (this.getServerTransport())(
+      this
+    );
+    /** @type {WebSocketServerImplementation} */
+    (this.webSocketServer).implementation.on(
+      "connection",
+      /**
+       * @param {ClientConnection} client
+       * @param {IncomingMessage} request
+       */
+      (client, request) => {
+        /** @type {{ [key: string]: string | undefined } | undefined} */
+        const headers =
+          // eslint-disable-next-line no-nested-ternary
+          typeof request !== "undefined"
+            ? /** @type {{ [key: string]: string | undefined }} */
+              (request.headers)
+            : typeof (
+                /** @type {import("sockjs").Connection} */ (client).headers
+              ) !== "undefined"
+            ? /** @type {import("sockjs").Connection} */ (client).headers
+            : // eslint-disable-next-line no-undefined
+              undefined;
+
+        if (!headers) {
+          this.logger.warn(
+            'webSocketServer implementation must pass headers for the "connection" event'
+          );
+        }
+
+        if (
+          !headers ||
+          !this.checkHeader(headers, "host") ||
+          !this.checkHeader(headers, "origin")
+        ) {
+          this.sendMessage([client], "error", "Invalid Host/Origin header");
+
+          // With https enabled, the sendMessage above is encrypted asynchronously so not yet sent
+          // Terminate would prevent it sending, so use close to allow it to be sent
+          client.close();
+
+          return;
+        }
+
+        if (this.options.hot === true || this.options.hot === "only") {
+          this.sendMessage([client], "hot");
+        }
+
+        if (this.options.liveReload) {
+          this.sendMessage([client], "liveReload");
+        }
+
+        if (
+          this.options.client &&
+          /** @type {ClientConfiguration} */
+          (this.options.client).progress
+        ) {
+          this.sendMessage(
+            [client],
+            "progress",
+            /** @type {ClientConfiguration} */
+            (this.options.client).progress
+          );
+        }
+
+        if (
+          this.options.client &&
+          /** @type {ClientConfiguration} */ (this.options.client).reconnect
+        ) {
+          this.sendMessage(
+            [client],
+            "reconnect",
+            /** @type {ClientConfiguration} */
+            (this.options.client).reconnect
+          );
+        }
+
+        if (
+          this.options.client &&
+          /** @type {ClientConfiguration} */
+          (this.options.client).overlay
+        ) {
+          const overlayConfig = /** @type {ClientConfiguration} */ (
+            this.options.client
+          ).overlay;
+
+          this.sendMessage(
+            [client],
+            "overlay",
+            typeof overlayConfig === "object"
+              ? {
+                  ...overlayConfig,
+                  errors:
+                    overlayConfig.errors &&
+                    encodeOverlaySettings(overlayConfig.errors),
+                  warnings:
+                    overlayConfig.warnings &&
+                    encodeOverlaySettings(overlayConfig.warnings),
+                  runtimeErrors:
+                    overlayConfig.runtimeErrors &&
+                    encodeOverlaySettings(overlayConfig.runtimeErrors),
+                }
+              : overlayConfig
+          );
+        }
+
+        if (!this.stats) {
+          return;
+        }
+
+        this.sendStats([client], this.getStats(this.stats), true);
+      }
+    );
+  }
+
+  /**
+   * @private
+   * @param {string} defaultOpenTarget
+   * @returns {void}
+   */
+  openBrowser(defaultOpenTarget) {
+    const open = require("open");
+
+    Promise.all(
+      /** @type {NormalizedOpen[]} */
+      (this.options.open).map((item) => {
+        /**
+         * @type {string}
+         */
+        let openTarget;
+
+        if (item.target === "<url>") {
+          openTarget = defaultOpenTarget;
+        } else {
+          openTarget = Server.isAbsoluteURL(item.target)
+            ? item.target
+            : new URL(item.target, defaultOpenTarget).toString();
+        }
+
+        return open(openTarget, item.options).catch(() => {
+          this.logger.warn(
+            `Unable to open "${openTarget}" page${
+              item.options.app
+                ? ` in "${
+                    /** @type {import("open").App} */
+                    (item.options.app).name
+                  }" app${
+                    /** @type {import("open").App} */
+                    (item.options.app).arguments
+                      ? ` with "${
+                          /** @type {import("open").App} */
+                          (item.options.app).arguments.join(" ")
+                        }" arguments`
+                      : ""
+                  }`
+                : ""
+            }. If you are running in a headless environment, please do not use the "open" option or related flags like "--open", "--open-target", and "--open-app".`
+          );
+        });
+      })
+    );
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  runBonjour() {
+    const { Bonjour } = require("bonjour-service");
+    /**
+     * @private
+     * @type {Bonjour | undefined}
+     */
+    this.bonjour = new Bonjour();
+    this.bonjour.publish({
+      // @ts-expect-error
+      name: `Webpack Dev Server ${os.hostname()}:${this.options.port}`,
+      // @ts-expect-error
+      port: /** @type {number} */ (this.options.port),
+      // @ts-expect-error
+      type:
+        /** @type {ServerConfiguration} */
+        (this.options.server).type === "http" ? "http" : "https",
+      subtypes: ["webpack"],
+      .../** @type {BonjourOptions} */ (this.options.bonjour),
+    });
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  stopBonjour(callback = () => {}) {
+    /** @type {Bonjour} */
+    (this.bonjour).unpublishAll(() => {
+      /** @type {Bonjour} */
+      (this.bonjour).destroy();
+
+      if (callback) {
+        callback();
+      }
+    });
+  }
+
+  /**
+   * @private
+   * @returns {void}
+   */
+  logStatus() {
+    const { isColorSupported, cyan, red } = require("colorette");
+
+    /**
+     * @param {Compiler["options"]} compilerOptions
+     * @returns {boolean}
+     */
+    const getColorsOption = (compilerOptions) => {
+      /**
+       * @type {boolean}
+       */
+      let colorsEnabled;
+
+      if (
+        compilerOptions.stats &&
+        typeof (/** @type {StatsOptions} */ (compilerOptions.stats).colors) !==
+          "undefined"
+      ) {
+        colorsEnabled =
+          /** @type {boolean} */
+          (/** @type {StatsOptions} */ (compilerOptions.stats).colors);
+      } else {
+        colorsEnabled = isColorSupported;
+      }
+
+      return colorsEnabled;
+    };
+
+    const colors = {
+      /**
+       * @param {boolean} useColor
+       * @param {string} msg
+       * @returns {string}
+       */
+      info(useColor, msg) {
+        if (useColor) {
+          return cyan(msg);
+        }
+
+        return msg;
+      },
+      /**
+       * @param {boolean} useColor
+       * @param {string} msg
+       * @returns {string}
+       */
+      error(useColor, msg) {
+        if (useColor) {
+          return red(msg);
+        }
+
+        return msg;
+      },
+    };
+    const useColor = getColorsOption(this.getCompilerOptions());
+
+    if (this.options.ipc) {
+      this.logger.info(
+        `Project is running at: "${
+          /** @type {import("http").Server} */
+          (this.server).address()
+        }"`
+      );
+    } else {
+      const protocol =
+        /** @type {ServerConfiguration} */
+        (this.options.server).type === "http" ? "http" : "https";
+      const { address, port } =
+        /** @type {import("net").AddressInfo} */
+        (
+          /** @type {import("http").Server} */
+          (this.server).address()
+        );
+      /**
+       * @param {string} newHostname
+       * @returns {string}
+       */
+      const prettyPrintURL = (newHostname) =>
+        url.format({ protocol, hostname: newHostname, port, pathname: "/" });
+
+      let server;
+      let localhost;
+      let loopbackIPv4;
+      let loopbackIPv6;
+      let networkUrlIPv4;
+      let networkUrlIPv6;
+
+      if (this.options.host) {
+        if (this.options.host === "localhost") {
+          localhost = prettyPrintURL("localhost");
+        } else {
+          let isIP;
+
+          try {
+            isIP = ipaddr.parse(this.options.host);
+          } catch (error) {
+            // Ignore
+          }
+
+          if (!isIP) {
+            server = prettyPrintURL(this.options.host);
+          }
+        }
+      }
+
+      const parsedIP = ipaddr.parse(address);
+
+      if (parsedIP.range() === "unspecified") {
+        localhost = prettyPrintURL("localhost");
+
+        const networkIPv4 = Server.internalIPSync("v4");
+
+        if (networkIPv4) {
+          networkUrlIPv4 = prettyPrintURL(networkIPv4);
+        }
+
+        const networkIPv6 = Server.internalIPSync("v6");
+
+        if (networkIPv6) {
+          networkUrlIPv6 = prettyPrintURL(networkIPv6);
+        }
+      } else if (parsedIP.range() === "loopback") {
+        if (parsedIP.kind() === "ipv4") {
+          loopbackIPv4 = prettyPrintURL(parsedIP.toString());
+        } else if (parsedIP.kind() === "ipv6") {
+          loopbackIPv6 = prettyPrintURL(parsedIP.toString());
+        }
+      } else {
+        networkUrlIPv4 =
+          parsedIP.kind() === "ipv6" &&
+          /** @type {IPv6} */
+          (parsedIP).isIPv4MappedAddress()
+            ? prettyPrintURL(
+                /** @type {IPv6} */
+                (parsedIP).toIPv4Address().toString()
+              )
+            : prettyPrintURL(address);
+
+        if (parsedIP.kind() === "ipv6") {
+          networkUrlIPv6 = prettyPrintURL(address);
+        }
+      }
+
+      this.logger.info("Project is running at:");
+
+      if (server) {
+        this.logger.info(`Server: ${colors.info(useColor, server)}`);
+      }
+
+      if (localhost || loopbackIPv4 || loopbackIPv6) {
+        const loopbacks = [];
+
+        if (localhost) {
+          loopbacks.push([colors.info(useColor, localhost)]);
+        }
+
+        if (loopbackIPv4) {
+          loopbacks.push([colors.info(useColor, loopbackIPv4)]);
+        }
+
+        if (loopbackIPv6) {
+          loopbacks.push([colors.info(useColor, loopbackIPv6)]);
+        }
+
+        this.logger.info(`Loopback: ${loopbacks.join(", ")}`);
+      }
+
+      if (networkUrlIPv4) {
+        this.logger.info(
+          `On Your Network (IPv4): ${colors.info(useColor, networkUrlIPv4)}`
+        );
+      }
+
+      if (networkUrlIPv6) {
+        this.logger.info(
+          `On Your Network (IPv6): ${colors.info(useColor, networkUrlIPv6)}`
+        );
+      }
+
+      if (/** @type {NormalizedOpen[]} */ (this.options.open).length > 0) {
+        const openTarget = prettyPrintURL(
+          !this.options.host ||
+            this.options.host === "0.0.0.0" ||
+            this.options.host === "::"
+            ? "localhost"
+            : this.options.host
+        );
+
+        this.openBrowser(openTarget);
+      }
+    }
+
+    if (/** @type {NormalizedStatic[]} */ (this.options.static).length > 0) {
+      this.logger.info(
+        `Content not from webpack is served from '${colors.info(
+          useColor,
+          /** @type {NormalizedStatic[]} */
+          (this.options.static)
+            .map((staticOption) => staticOption.directory)
+            .join(", ")
+        )}' directory`
+      );
+    }
+
+    if (this.options.historyApiFallback) {
+      this.logger.info(
+        `404s will fallback to '${colors.info(
+          useColor,
+          /** @type {ConnectHistoryApiFallbackOptions} */ (
+            this.options.historyApiFallback
+          ).index || "/index.html"
+        )}'`
+      );
+    }
+
+    if (this.options.bonjour) {
+      const bonjourProtocol =
+        /** @type {BonjourOptions} */
+        (this.options.bonjour).type ||
+        /** @type {ServerConfiguration} */
+        (this.options.server).type === "http"
+          ? "http"
+          : "https";
+
+      this.logger.info(
+        `Broadcasting "${bonjourProtocol}" with subtype of "webpack" via ZeroConf DNS (Bonjour)`
+      );
+    }
+  }
+
+  /**
+   * @private
+   * @param {Request} req
+   * @param {Response} res
+   * @param {NextFunction} next
+   */
+  setHeaders(req, res, next) {
+    let { headers } = this.options;
+
+    if (headers) {
+      if (typeof headers === "function") {
+        headers = headers(
+          req,
+          res,
+          /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
+          (this.middleware).context
+        );
+      }
+
+      /**
+       * @type {{key: string, value: string}[]}
+       */
+      const allHeaders = [];
+
+      if (!Array.isArray(headers)) {
+        // eslint-disable-next-line guard-for-in
+        for (const name in headers) {
+          // @ts-ignore
+          allHeaders.push({ key: name, value: headers[name] });
+        }
+
+        headers = allHeaders;
+      }
+
+      headers.forEach(
+        /**
+         * @param {{key: string, value: any}} header
+         */
+        (header) => {
+          res.setHeader(header.key, header.value);
+        }
+      );
+    }
+
+    next();
+  }
+
+  /**
+   * @private
+   * @param {{ [key: string]: string | undefined }} headers
+   * @param {string} headerToCheck
+   * @returns {boolean}
+   */
+  checkHeader(headers, headerToCheck) {
+    // allow user to opt out of this security check, at their own risk
+    // by explicitly enabling allowedHosts
+    if (this.options.allowedHosts === "all") {
+      return true;
+    }
+
+    // get the Host header and extract hostname
+    // we don't care about port not matching
+    const hostHeader = headers[headerToCheck];
+
+    if (!hostHeader) {
+      return false;
+    }
+
+    if (/^(file|.+-extension):/i.test(hostHeader)) {
+      return true;
+    }
+
+    // use the node url-parser to retrieve the hostname from the host-header.
+    const hostname = url.parse(
+      // if hostHeader doesn't have scheme, add // for parsing.
+      /^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`,
+      false,
+      true
+    ).hostname;
+
+    // always allow requests with explicit IPv4 or IPv6-address.
+    // A note on IPv6 addresses:
+    // hostHeader will always contain the brackets denoting
+    // an IPv6-address in URLs,
+    // these are removed from the hostname in url.parse(),
+    // so we have the pure IPv6-address in hostname.
+    // For convenience, always allow localhost (hostname === 'localhost')
+    // and its subdomains (hostname.endsWith(".localhost")).
+    // allow hostname of listening address  (hostname === this.options.host)
+    const isValidHostname =
+      (hostname !== null && ipaddr.IPv4.isValid(hostname)) ||
+      (hostname !== null && ipaddr.IPv6.isValid(hostname)) ||
+      hostname === "localhost" ||
+      (hostname !== null && hostname.endsWith(".localhost")) ||
+      hostname === this.options.host;
+
+    if (isValidHostname) {
+      return true;
+    }
+
+    const { allowedHosts } = this.options;
+
+    // always allow localhost host, for convenience
+    // allow if hostname is in allowedHosts
+    if (Array.isArray(allowedHosts) && allowedHosts.length > 0) {
+      for (let hostIdx = 0; hostIdx < allowedHosts.length; hostIdx++) {
+        const allowedHost = allowedHosts[hostIdx];
+
+        if (allowedHost === hostname) {
+          return true;
+        }
+
+        // support "." as a subdomain wildcard
+        // e.g. ".example.com" will allow "example.com", "www.example.com", "subdomain.example.com", etc
+        if (allowedHost[0] === ".") {
+          // "example.com"  (hostname === allowedHost.substring(1))
+          // "*.example.com"  (hostname.endsWith(allowedHost))
+          if (
+            hostname === allowedHost.substring(1) ||
+            /** @type {string} */ (hostname).endsWith(allowedHost)
+          ) {
+            return true;
+          }
+        }
+      }
+    }
+
+    // Also allow if `client.webSocketURL.hostname` provided
+    if (
+      this.options.client &&
+      typeof (
+        /** @type {ClientConfiguration} */ (this.options.client).webSocketURL
+      ) !== "undefined"
+    ) {
+      return (
+        /** @type {WebSocketURL} */
+        (/** @type {ClientConfiguration} */ (this.options.client).webSocketURL)
+          .hostname === hostname
+      );
+    }
+
+    // disallow
+    return false;
+  }
+
+  /**
+   * @param {ClientConnection[]} clients
+   * @param {string} type
+   * @param {any} [data]
+   * @param {any} [params]
+   */
+  // eslint-disable-next-line class-methods-use-this
+  sendMessage(clients, type, data, params) {
+    for (const client of clients) {
+      // `sockjs` uses `1` to indicate client is ready to accept data
+      // `ws` uses `WebSocket.OPEN`, but it is mean `1` too
+      if (client.readyState === 1) {
+        client.send(JSON.stringify({ type, data, params }));
+      }
+    }
+  }
+
+  /**
+   * @private
+   * @param {Request} req
+   * @param {Response} res
+   * @param {NextFunction} next
+   * @returns {void}
+   */
+  serveMagicHtml(req, res, next) {
+    if (req.method !== "GET" && req.method !== "HEAD") {
+      return next();
+    }
+
+    /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
+    (this.middleware).waitUntilValid(() => {
+      const _path = req.path;
+
+      try {
+        const filename =
+          /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
+          (this.middleware).getFilenameFromUrl(`${_path}.js`);
+        const isFile =
+          /** @type {Compiler["outputFileSystem"] & { statSync: import("fs").StatSyncFn }}*/
+          (
+            /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
+            (this.middleware).context.outputFileSystem
+          )
+            .statSync(/** @type {import("fs").PathLike} */ (filename))
+            .isFile();
+
+        if (!isFile) {
+          return next();
+        }
+
+        // Serve a page that executes the javascript
+        // @ts-ignore
+        const queries = req._parsedUrl.search || "";
+        const responsePage = `<!DOCTYPE html><html><head><meta charset="utf-8"/></head><body><script type="text/javascript" charset="utf-8" src="${_path}.js${queries}"></script></body></html>`;
+
+        res.send(responsePage);
+      } catch (error) {
+        return next();
+      }
+    });
+  }
+
+  // Send stats to a socket or multiple sockets
+  /**
+   * @private
+   * @param {ClientConnection[]} clients
+   * @param {StatsCompilation} stats
+   * @param {boolean} [force]
+   */
+  sendStats(clients, stats, force) {
+    const shouldEmit =
+      !force &&
+      stats &&
+      (!stats.errors || stats.errors.length === 0) &&
+      (!stats.warnings || stats.warnings.length === 0) &&
+      this.currentHash === stats.hash;
+
+    if (shouldEmit) {
+      this.sendMessage(clients, "still-ok");
+
+      return;
+    }
+
+    this.currentHash = stats.hash;
+    this.sendMessage(clients, "hash", stats.hash);
+
+    if (
+      /** @type {NonNullable<StatsCompilation["errors"]>} */
+      (stats.errors).length > 0 ||
+      /** @type {NonNullable<StatsCompilation["warnings"]>} */
+      (stats.warnings).length > 0
+    ) {
+      const hasErrors =
+        /** @type {NonNullable<StatsCompilation["errors"]>} */
+        (stats.errors).length > 0;
+
+      if (
+        /** @type {NonNullable<StatsCompilation["warnings"]>} */
+        (stats.warnings).length > 0
+      ) {
+        let params;
+
+        if (hasErrors) {
+          params = { preventReloading: true };
+        }
+
+        this.sendMessage(clients, "warnings", stats.warnings, params);
+      }
+
+      if (
+        /** @type {NonNullable<StatsCompilation["errors"]>} */ (stats.errors)
+          .length > 0
+      ) {
+        this.sendMessage(clients, "errors", stats.errors);
+      }
+    } else {
+      this.sendMessage(clients, "ok");
+    }
+  }
+
+  /**
+   * @param {string | string[]} watchPath
+   * @param {WatchOptions} [watchOptions]
+   */
+  watchFiles(watchPath, watchOptions) {
+    const chokidar = require("chokidar");
+    const watcher = chokidar.watch(watchPath, watchOptions);
+
+    // disabling refreshing on changing the content
+    if (this.options.liveReload) {
+      watcher.on("change", (item) => {
+        if (this.webSocketServer) {
+          this.sendMessage(
+            this.webSocketServer.clients,
+            "static-changed",
+            item
+          );
+        }
+      });
+    }
+
+    this.staticWatchers.push(watcher);
+  }
+
+  /**
+   * @param {import("webpack-dev-middleware").Callback} [callback]
+   */
+  invalidate(callback = () => {}) {
+    if (this.middleware) {
+      this.middleware.invalidate(callback);
+    }
+  }
+
+  /**
+   * @returns {Promise<void>}
+   */
+  async start() {
+    await this.normalizeOptions();
+
+    if (this.options.ipc) {
+      await /** @type {Promise<void>} */ (
+        new Promise((resolve, reject) => {
+          const net = require("net");
+          const socket = new net.Socket();
+
+          socket.on(
+            "error",
+            /**
+             * @param {Error & { code?: string }} error
+             */
+            (error) => {
+              if (error.code === "ECONNREFUSED") {
+                // No other server listening on this socket, so it can be safely removed
+                fs.unlinkSync(/** @type {string} */ (this.options.ipc));
+
+                resolve();
+
+                return;
+              } else if (error.code === "ENOENT") {
+                resolve();
+
+                return;
+              }
+
+              reject(error);
+            }
+          );
+
+          socket.connect(
+            { path: /** @type {string} */ (this.options.ipc) },
+            () => {
+              throw new Error(`IPC "${this.options.ipc}" is already used`);
+            }
+          );
+        })
+      );
+    } else {
+      this.options.host = await Server.getHostname(
+        /** @type {Host} */ (this.options.host)
+      );
+      this.options.port = await Server.getFreePort(
+        /** @type {Port} */ (this.options.port),
+        this.options.host
+      );
+    }
+
+    await this.initialize();
+
+    const listenOptions = this.options.ipc
+      ? { path: this.options.ipc }
+      : { host: this.options.host, port: this.options.port };
+
+    await /** @type {Promise<void>} */ (
+      new Promise((resolve) => {
+        /** @type {import("http").Server} */
+        (this.server).listen(listenOptions, () => {
+          resolve();
+        });
+      })
+    );
+
+    if (this.options.ipc) {
+      // chmod 666 (rw rw rw)
+      const READ_WRITE = 438;
+
+      await fs.promises.chmod(
+        /** @type {string} */ (this.options.ipc),
+        READ_WRITE
+      );
+    }
+
+    if (this.options.webSocketServer) {
+      this.createWebSocketServer();
+    }
+
+    if (this.options.bonjour) {
+      this.runBonjour();
+    }
+
+    this.logStatus();
+
+    if (typeof this.options.onListening === "function") {
+      this.options.onListening(this);
+    }
+  }
+
+  /**
+   * @param {(err?: Error) => void} [callback]
+   */
+  startCallback(callback = () => {}) {
+    this.start()
+      .then(() => callback(), callback)
+      .catch(callback);
+  }
+
+  /**
+   * @returns {Promise<void>}
+   */
+  async stop() {
+    if (this.bonjour) {
+      await /** @type {Promise<void>} */ (
+        new Promise((resolve) => {
+          this.stopBonjour(() => {
+            resolve();
+          });
+        })
+      );
+    }
+
+    this.webSocketProxies = [];
+
+    await Promise.all(this.staticWatchers.map((watcher) => watcher.close()));
+
+    this.staticWatchers = [];
+
+    if (this.webSocketServer) {
+      await /** @type {Promise<void>} */ (
+        new Promise((resolve) => {
+          /** @type {WebSocketServerImplementation} */
+          (this.webSocketServer).implementation.close(() => {
+            this.webSocketServer = null;
+
+            resolve();
+          });
+
+          for (const client of /** @type {WebSocketServerImplementation} */ (
+            this.webSocketServer
+          ).clients) {
+            client.terminate();
+          }
+
+          /** @type {WebSocketServerImplementation} */
+          (this.webSocketServer).clients = [];
+        })
+      );
+    }
+
+    if (this.server) {
+      await /** @type {Promise<void>} */ (
+        new Promise((resolve) => {
+          /** @type {import("http").Server} */
+          (this.server).close(() => {
+            this.server = null;
+
+            resolve();
+          });
+
+          for (const socket of this.sockets) {
+            socket.destroy();
+          }
+
+          this.sockets = [];
+        })
+      );
+
+      if (this.middleware) {
+        await /** @type {Promise<void>} */ (
+          new Promise((resolve, reject) => {
+            /** @type {import("webpack-dev-middleware").API<Request, Response>}*/
+            (this.middleware).close((error) => {
+              if (error) {
+                reject(error);
+
+                return;
+              }
+
+              resolve();
+            });
+          })
+        );
+
+        this.middleware = null;
+      }
+    }
+
+    // We add listeners to signals when creating a new Server instance
+    // So ensure they are removed to prevent EventEmitter memory leak warnings
+    for (const item of this.listeners) {
+      process.removeListener(item.name, item.listener);
+    }
+  }
+
+  /**
+   * @param {(err?: Error) => void} [callback]
+   */
+  stopCallback(callback = () => {}) {
+    this.stop()
+      .then(() => callback(), callback)
+      .catch(callback);
+  }
+
+  // TODO remove in the next major release
+  /**
+   * @param {Port} port
+   * @param {Host} hostname
+   * @param {(err?: Error) => void} fn
+   * @returns {void}
+   */
+  listen(port, hostname, fn) {
+    util.deprecate(
+      () => {},
+      "'listen' is deprecated. Please use the async 'start' or 'startCallback' method.",
+      "DEP_WEBPACK_DEV_SERVER_LISTEN"
+    )();
+
+    if (typeof port === "function") {
+      fn = port;
+    }
+
+    if (
+      typeof port !== "undefined" &&
+      typeof this.options.port !== "undefined" &&
+      port !== this.options.port
+    ) {
+      this.options.port = port;
+
+      this.logger.warn(
+        'The "port" specified in options is different from the port passed as an argument. Will be used from arguments.'
+      );
+    }
+
+    if (!this.options.port) {
+      this.options.port = port;
+    }
+
+    if (
+      typeof hostname !== "undefined" &&
+      typeof this.options.host !== "undefined" &&
+      hostname !== this.options.host
+    ) {
+      this.options.host = hostname;
+
+      this.logger.warn(
+        'The "host" specified in options is different from the host passed as an argument. Will be used from arguments.'
+      );
+    }
+
+    if (!this.options.host) {
+      this.options.host = hostname;
+    }
+
+    this.start()
+      .then(() => {
+        if (fn) {
+          fn.call(this.server);
+        }
+      })
+      .catch((error) => {
+        // Nothing
+        if (fn) {
+          fn.call(this.server, error);
+        }
+      });
+  }
+
+  /**
+   * @param {(err?: Error) => void} [callback]
+   * @returns {void}
+   */
+  // TODO remove in the next major release
+  close(callback) {
+    util.deprecate(
+      () => {},
+      "'close' is deprecated. Please use the async 'stop' or 'stopCallback' method.",
+      "DEP_WEBPACK_DEV_SERVER_CLOSE"
+    )();
+
+    this.stop()
+      .then(() => {
+        if (callback) {
+          callback();
+        }
+      })
+      .catch((error) => {
+        if (callback) {
+          callback(error);
+        }
+      });
+  }
+}
+
+module.exports = Server;
Index: frontend/node_modules/webpack-dev-server/lib/getPort.js
===================================================================
--- frontend/node_modules/webpack-dev-server/lib/getPort.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/lib/getPort.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,133 @@
+"use strict";
+
+/*
+ * Based on the packages get-port https://www.npmjs.com/package/get-port
+ * and portfinder https://www.npmjs.com/package/portfinder
+ * The code structure is similar to get-port, but it searches
+ * ports deterministically like portfinder
+ */
+const net = require("net");
+const os = require("os");
+
+const minPort = 1024;
+const maxPort = 65_535;
+
+/**
+ * @return {Set<string|undefined>}
+ */
+const getLocalHosts = () => {
+  const interfaces = os.networkInterfaces();
+
+  // Add undefined value for createServer function to use default host,
+  // and default IPv4 host in case createServer defaults to IPv6.
+  // eslint-disable-next-line no-undefined
+  const results = new Set([undefined, "0.0.0.0"]);
+
+  for (const _interface of Object.values(interfaces)) {
+    if (_interface) {
+      for (const config of _interface) {
+        results.add(config.address);
+      }
+    }
+  }
+
+  return results;
+};
+
+/**
+ * @param {number} basePort
+ * @param {string | undefined} host
+ * @return {Promise<number>}
+ */
+const checkAvailablePort = (basePort, host) =>
+  new Promise((resolve, reject) => {
+    const server = net.createServer();
+    server.unref();
+    server.on("error", reject);
+
+    server.listen(basePort, host, () => {
+      // Next line should return AdressInfo because we're calling it after listen() and before close()
+      const { port } = /** @type {import("net").AddressInfo} */ (
+        server.address()
+      );
+      server.close(() => {
+        resolve(port);
+      });
+    });
+  });
+
+/**
+ * @param {number} port
+ * @param {Set<string|undefined>} hosts
+ * @return {Promise<number>}
+ */
+const getAvailablePort = async (port, hosts) => {
+  /**
+   * Errors that mean that host is not available.
+   * @type {Set<string | undefined>}
+   */
+  const nonExistentInterfaceErrors = new Set(["EADDRNOTAVAIL", "EINVAL"]);
+  /* Check if the post is available on every local host name */
+  for (const host of hosts) {
+    try {
+      await checkAvailablePort(port, host); // eslint-disable-line no-await-in-loop
+    } catch (error) {
+      /* We throw an error only if the interface exists */
+      if (
+        !nonExistentInterfaceErrors.has(
+          /** @type {NodeJS.ErrnoException} */ (error).code
+        )
+      ) {
+        throw error;
+      }
+    }
+  }
+
+  return port;
+};
+
+/**
+ * @param {number} basePort
+ * @param {string=} host
+ * @return {Promise<number>}
+ */
+async function getPorts(basePort, host) {
+  if (basePort < minPort || basePort > maxPort) {
+    throw new Error(`Port number must lie between ${minPort} and ${maxPort}`);
+  }
+
+  let port = basePort;
+  const localhosts = getLocalHosts();
+  let hosts;
+  if (host && !localhosts.has(host)) {
+    hosts = new Set([host]);
+  } else {
+    /* If the host is equivalent to localhost
+       we need to check every equivalent host
+       else the port might falsely appear as available
+       on some operating systems  */
+    hosts = localhosts;
+  }
+  /** @type {Set<string | undefined>} */
+  const portUnavailableErrors = new Set(["EADDRINUSE", "EACCES"]);
+  while (port <= maxPort) {
+    try {
+      const availablePort = await getAvailablePort(port, hosts); // eslint-disable-line no-await-in-loop
+      return availablePort;
+    } catch (error) {
+      /* Try next port if port is busy; throw for any other error */
+      if (
+        !portUnavailableErrors.has(
+          /** @type {NodeJS.ErrnoException} */ (error).code
+        )
+      ) {
+        throw error;
+      }
+      port += 1;
+    }
+  }
+
+  throw new Error("No available ports found");
+}
+
+module.exports = getPorts;
Index: frontend/node_modules/webpack-dev-server/lib/options.json
===================================================================
--- frontend/node_modules/webpack-dev-server/lib/options.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/lib/options.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1266 @@
+{
+  "title": "Dev Server options",
+  "type": "object",
+  "definitions": {
+    "AllowedHosts": {
+      "anyOf": [
+        {
+          "type": "array",
+          "minItems": 1,
+          "items": {
+            "$ref": "#/definitions/AllowedHostsItem"
+          }
+        },
+        {
+          "enum": ["auto", "all"]
+        },
+        {
+          "$ref": "#/definitions/AllowedHostsItem"
+        }
+      ],
+      "description": "Allows to enumerate the hosts from which access to the dev server are allowed (useful when you are proxying dev server, by default is 'auto').",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverallowedhosts"
+    },
+    "AllowedHostsItem": {
+      "type": "string",
+      "minLength": 1
+    },
+    "Bonjour": {
+      "anyOf": [
+        {
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Disallows to broadcasts dev server via ZeroConf networking on start."
+          }
+        },
+        {
+          "type": "object",
+          "description": "Options for bonjour.",
+          "link": "https://github.com/watson/bonjour#initializing"
+        }
+      ],
+      "description": "Allows to broadcasts dev server via ZeroConf networking on start.",
+      "link": " https://webpack.js.org/configuration/dev-server/#devserverbonjour"
+    },
+    "Client": {
+      "description": "Allows to specify options for client script in the browser or disable client script.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverclient",
+      "anyOf": [
+        {
+          "enum": [false],
+          "cli": {
+            "negatedDescription": "Disables client script."
+          }
+        },
+        {
+          "type": "object",
+          "additionalProperties": false,
+          "properties": {
+            "logging": {
+              "$ref": "#/definitions/ClientLogging"
+            },
+            "overlay": {
+              "$ref": "#/definitions/ClientOverlay"
+            },
+            "progress": {
+              "$ref": "#/definitions/ClientProgress"
+            },
+            "reconnect": {
+              "$ref": "#/definitions/ClientReconnect"
+            },
+            "webSocketTransport": {
+              "$ref": "#/definitions/ClientWebSocketTransport"
+            },
+            "webSocketURL": {
+              "$ref": "#/definitions/ClientWebSocketURL"
+            }
+          }
+        }
+      ]
+    },
+    "ClientLogging": {
+      "enum": ["none", "error", "warn", "info", "log", "verbose"],
+      "description": "Allows to set log level in the browser.",
+      "link": "https://webpack.js.org/configuration/dev-server/#logging"
+    },
+    "ClientOverlay": {
+      "anyOf": [
+        {
+          "description": "Enables a full-screen overlay in the browser when there are compiler errors or warnings.",
+          "link": "https://webpack.js.org/configuration/dev-server/#overlay",
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler errors or warnings."
+          }
+        },
+        {
+          "type": "object",
+          "additionalProperties": false,
+          "properties": {
+            "errors": {
+              "anyOf": [
+                {
+                  "description": "Enables a full-screen overlay in the browser when there are compiler errors.",
+                  "type": "boolean",
+                  "cli": {
+                    "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler errors."
+                  }
+                },
+                {
+                  "instanceof": "Function",
+                  "description": "Filter compiler errors. Return true to include and return false to exclude."
+                }
+              ]
+            },
+            "warnings": {
+              "anyOf": [
+                {
+                  "description": "Enables a full-screen overlay in the browser when there are compiler warnings.",
+                  "type": "boolean",
+                  "cli": {
+                    "negatedDescription": "Disables the full-screen overlay in the browser when there are compiler warnings."
+                  }
+                },
+                {
+                  "instanceof": "Function",
+                  "description": "Filter compiler warnings. Return true to include and return false to exclude."
+                }
+              ]
+            },
+            "runtimeErrors": {
+              "anyOf": [
+                {
+                  "description": "Enables a full-screen overlay in the browser when there are uncaught runtime errors.",
+                  "type": "boolean",
+                  "cli": {
+                    "negatedDescription": "Disables the full-screen overlay in the browser when there are uncaught runtime errors."
+                  }
+                },
+                {
+                  "instanceof": "Function",
+                  "description": "Filter uncaught runtime errors. Return true to include and return false to exclude."
+                }
+              ]
+            },
+            "trustedTypesPolicyName": {
+              "description": "The name of a Trusted Types policy for the overlay. Defaults to 'webpack-dev-server#overlay'.",
+              "type": "string"
+            }
+          }
+        }
+      ]
+    },
+    "ClientProgress": {
+      "description": "Prints compilation progress in percentage in the browser.",
+      "link": "https://webpack.js.org/configuration/dev-server/#progress",
+      "type": "boolean",
+      "cli": {
+        "negatedDescription": "Does not print compilation progress in percentage in the browser."
+      }
+    },
+    "ClientReconnect": {
+      "description": "Tells dev-server the number of times it should try to reconnect the client.",
+      "link": "https://webpack.js.org/configuration/dev-server/#reconnect",
+      "anyOf": [
+        {
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Tells dev-server to not to try to reconnect the client."
+          }
+        },
+        {
+          "type": "number",
+          "minimum": 0
+        }
+      ]
+    },
+    "ClientWebSocketTransport": {
+      "anyOf": [
+        {
+          "$ref": "#/definitions/ClientWebSocketTransportEnum"
+        },
+        {
+          "$ref": "#/definitions/ClientWebSocketTransportString"
+        }
+      ],
+      "description": "Allows to set custom web socket transport to communicate with dev server.",
+      "link": "https://webpack.js.org/configuration/dev-server/#websockettransport"
+    },
+    "ClientWebSocketTransportEnum": {
+      "enum": ["sockjs", "ws"]
+    },
+    "ClientWebSocketTransportString": {
+      "type": "string",
+      "minLength": 1
+    },
+    "ClientWebSocketURL": {
+      "description": "Allows to specify URL to web socket server (useful when you're proxying dev server and client script does not always know where to connect to).",
+      "link": "https://webpack.js.org/configuration/dev-server/#websocketurl",
+      "anyOf": [
+        {
+          "type": "string",
+          "minLength": 1
+        },
+        {
+          "type": "object",
+          "additionalProperties": false,
+          "properties": {
+            "hostname": {
+              "description": "Tells clients connected to devServer to use the provided hostname.",
+              "type": "string",
+              "minLength": 1
+            },
+            "pathname": {
+              "description": "Tells clients connected to devServer to use the provided path to connect.",
+              "type": "string"
+            },
+            "password": {
+              "description": "Tells clients connected to devServer to use the provided password to authenticate.",
+              "type": "string"
+            },
+            "port": {
+              "description": "Tells clients connected to devServer to use the provided port.",
+              "anyOf": [
+                {
+                  "type": "number"
+                },
+                {
+                  "type": "string",
+                  "minLength": 1
+                }
+              ]
+            },
+            "protocol": {
+              "description": "Tells clients connected to devServer to use the provided protocol.",
+              "anyOf": [
+                {
+                  "enum": ["auto"]
+                },
+                {
+                  "type": "string",
+                  "minLength": 1
+                }
+              ]
+            },
+            "username": {
+              "description": "Tells clients connected to devServer to use the provided username to authenticate.",
+              "type": "string"
+            }
+          }
+        }
+      ]
+    },
+    "Compress": {
+      "type": "boolean",
+      "description": "Enables gzip compression for everything served.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devservercompress",
+      "cli": {
+        "negatedDescription": "Disables gzip compression for everything served."
+      }
+    },
+    "DevMiddleware": {
+      "description": "Provide options to 'webpack-dev-middleware' which handles webpack assets.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverdevmiddleware",
+      "type": "object",
+      "additionalProperties": true
+    },
+    "HTTP2": {
+      "type": "boolean",
+      "description": "Allows to serve over HTTP/2 using SPDY. Deprecated, use the `server` option.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverhttp2",
+      "cli": {
+        "negatedDescription": "Does not serve over HTTP/2 using SPDY."
+      }
+    },
+    "HTTPS": {
+      "anyOf": [
+        {
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Disallows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP)."
+          }
+        },
+        {
+          "type": "object",
+          "additionalProperties": true,
+          "properties": {
+            "passphrase": {
+              "type": "string",
+              "description": "Passphrase for a pfx file. Deprecated, use the `server.options.passphrase` option."
+            },
+            "requestCert": {
+              "type": "boolean",
+              "description": "Request for an SSL certificate. Deprecated, use the `server.options.requestCert` option.",
+              "cli": {
+                "negatedDescription": "Does not request for an SSL certificate."
+              }
+            },
+            "ca": {
+              "anyOf": [
+                {
+                  "type": "array",
+                  "items": {
+                    "anyOf": [
+                      {
+                        "type": "string"
+                      },
+                      {
+                        "instanceof": "Buffer"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "type": "string"
+                },
+                {
+                  "instanceof": "Buffer"
+                }
+              ],
+              "description": "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option."
+            },
+            "cacert": {
+              "anyOf": [
+                {
+                  "type": "array",
+                  "items": {
+                    "anyOf": [
+                      {
+                        "type": "string"
+                      },
+                      {
+                        "instanceof": "Buffer"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "type": "string"
+                },
+                {
+                  "instanceof": "Buffer"
+                }
+              ],
+              "description": "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option."
+            },
+            "cert": {
+              "anyOf": [
+                {
+                  "type": "array",
+                  "items": {
+                    "anyOf": [
+                      {
+                        "type": "string"
+                      },
+                      {
+                        "instanceof": "Buffer"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "type": "string"
+                },
+                {
+                  "instanceof": "Buffer"
+                }
+              ],
+              "description": "Path to an SSL certificate or content of an SSL certificate. Deprecated, use the `server.options.cert` option."
+            },
+            "crl": {
+              "anyOf": [
+                {
+                  "type": "array",
+                  "items": {
+                    "anyOf": [
+                      {
+                        "type": "string"
+                      },
+                      {
+                        "instanceof": "Buffer"
+                      }
+                    ]
+                  }
+                },
+                {
+                  "type": "string"
+                },
+                {
+                  "instanceof": "Buffer"
+                }
+              ],
+              "description": "Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists). Deprecated, use the `server.options.crl` option."
+            },
+            "key": {
+              "anyOf": [
+                {
+                  "type": "array",
+                  "items": {
+                    "anyOf": [
+                      {
+                        "type": "string"
+                      },
+                      {
+                        "instanceof": "Buffer"
+                      },
+                      {
+                        "type": "object",
+                        "additionalProperties": true
+                      }
+                    ]
+                  }
+                },
+                {
+                  "type": "string"
+                },
+                {
+                  "instanceof": "Buffer"
+                }
+              ],
+              "description": "Path to an SSL key or content of an SSL key. Deprecated, use the `server.options.key` option."
+            },
+            "pfx": {
+              "anyOf": [
+                {
+                  "type": "array",
+                  "items": {
+                    "anyOf": [
+                      {
+                        "type": "string"
+                      },
+                      {
+                        "instanceof": "Buffer"
+                      },
+                      {
+                        "type": "object",
+                        "additionalProperties": true
+                      }
+                    ]
+                  }
+                },
+                {
+                  "type": "string"
+                },
+                {
+                  "instanceof": "Buffer"
+                }
+              ],
+              "description": "Path to an SSL pfx file or content of an SSL pfx file. Deprecated, use the `server.options.pfx` option."
+            }
+          }
+        }
+      ],
+      "description": "Allows to configure the server's listening socket for TLS (by default, dev server will be served over HTTP). Deprecated, use the `server` option.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverhttps"
+    },
+    "HeaderObject": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "key": {
+          "description": "key of header.",
+          "type": "string"
+        },
+        "value": {
+          "description": "value of header.",
+          "type": "string"
+        }
+      },
+      "cli": {
+        "exclude": true
+      }
+    },
+    "Headers": {
+      "anyOf": [
+        {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/HeaderObject"
+          },
+          "minItems": 1
+        },
+        {
+          "type": "object"
+        },
+        {
+          "instanceof": "Function"
+        }
+      ],
+      "description": "Allows to set custom headers on response.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverheaders"
+    },
+    "HistoryApiFallback": {
+      "anyOf": [
+        {
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Disallows to proxy requests through a specified index page."
+          }
+        },
+        {
+          "type": "object",
+          "description": "Options for `historyApiFallback`.",
+          "link": "https://github.com/bripkens/connect-history-api-fallback#options"
+        }
+      ],
+      "description": "Allows to proxy requests through a specified index page (by default 'index.html'), useful for Single Page Applications that utilise the HTML5 History API.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverhistoryapifallback"
+    },
+    "Host": {
+      "description": "Allows to specify a hostname to use.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverhost",
+      "anyOf": [
+        {
+          "enum": ["local-ip", "local-ipv4", "local-ipv6"]
+        },
+        {
+          "type": "string",
+          "minLength": 1
+        }
+      ]
+    },
+    "Hot": {
+      "anyOf": [
+        {
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Disables Hot Module Replacement."
+          }
+        },
+        {
+          "enum": ["only"]
+        }
+      ],
+      "description": "Enables Hot Module Replacement.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverhot"
+    },
+    "IPC": {
+      "anyOf": [
+        {
+          "type": "string",
+          "minLength": 1
+        },
+        {
+          "type": "boolean",
+          "enum": [true]
+        }
+      ],
+      "description": "Listen to a unix socket.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserveripc"
+    },
+    "LiveReload": {
+      "type": "boolean",
+      "description": "Enables reload/refresh the page(s) when file changes are detected (enabled by default).",
+      "cli": {
+        "negatedDescription": "Disables reload/refresh the page(s) when file changes are detected (enabled by default)."
+      },
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverlivereload"
+    },
+    "MagicHTML": {
+      "type": "boolean",
+      "description": "Tells dev-server whether to enable magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js').",
+      "cli": {
+        "negatedDescription": "Disables magic HTML routes (routes corresponding to your webpack output, for example '/main' for 'main.js')."
+      },
+      "link": "https://webpack.js.org/configuration/dev-server/#devservermagichtml"
+    },
+    "OnAfterSetupMiddleware": {
+      "instanceof": "Function",
+      "description": "Provides the ability to execute a custom function and apply custom middleware(s) after all other middlewares. Deprecated: please use the 'setupMiddlewares' option.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserveronaftersetupmiddleware"
+    },
+    "OnBeforeSetupMiddleware": {
+      "instanceof": "Function",
+      "description": "Provides the ability to execute a custom function and apply custom middleware(s) prior to all other middlewares. Deprecated: please use the 'setupMiddlewares' option.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserveronbeforesetupmiddleware"
+    },
+    "OnListening": {
+      "instanceof": "Function",
+      "description": "Provides the ability to execute a custom function when dev server starts listening.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserveronlistening"
+    },
+    "Open": {
+      "anyOf": [
+        {
+          "type": "array",
+          "items": {
+            "anyOf": [
+              {
+                "$ref": "#/definitions/OpenString"
+              },
+              {
+                "$ref": "#/definitions/OpenObject"
+              }
+            ]
+          }
+        },
+        {
+          "$ref": "#/definitions/OpenBoolean"
+        },
+        {
+          "$ref": "#/definitions/OpenString"
+        },
+        {
+          "$ref": "#/definitions/OpenObject"
+        }
+      ],
+      "description": "Allows to configure dev server to open the browser(s) and page(s) after server had been started (set it to true to open your default browser).",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserveropen"
+    },
+    "OpenBoolean": {
+      "type": "boolean",
+      "cli": {
+        "negatedDescription": "Does not open the default browser."
+      }
+    },
+    "OpenObject": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "target": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "description": "Opens specified page in browser."
+        },
+        "app": {
+          "anyOf": [
+            {
+              "type": "object",
+              "additionalProperties": false,
+              "properties": {
+                "name": {
+                  "anyOf": [
+                    {
+                      "type": "array",
+                      "items": {
+                        "type": "string",
+                        "minLength": 1
+                      },
+                      "minItems": 1
+                    },
+                    {
+                      "type": "string",
+                      "minLength": 1
+                    }
+                  ]
+                },
+                "arguments": {
+                  "items": {
+                    "type": "string",
+                    "minLength": 1
+                  }
+                }
+              }
+            },
+            {
+              "type": "string",
+              "minLength": 1,
+              "description": "Open specified browser.",
+              "cli": {
+                "description": "Open specified browser. Deprecated: please use '--open-app-name'."
+              }
+            }
+          ],
+          "description": "Open specified browser."
+        }
+      }
+    },
+    "OpenString": {
+      "type": "string",
+      "minLength": 1
+    },
+    "Port": {
+      "anyOf": [
+        {
+          "type": "number",
+          "minimum": 0,
+          "maximum": 65535
+        },
+        {
+          "type": "string",
+          "minLength": 1
+        },
+        {
+          "enum": ["auto"]
+        }
+      ],
+      "description": "Allows to specify a port to use.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverport"
+    },
+    "Proxy": {
+      "anyOf": [
+        {
+          "type": "object"
+        },
+        {
+          "type": "array",
+          "items": {
+            "anyOf": [
+              {
+                "type": "object"
+              },
+              {
+                "instanceof": "Function"
+              }
+            ]
+          }
+        }
+      ],
+      "description": "Allows to proxy requests, can be useful when you have a separate API backend development server and you want to send API requests on the same domain.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverproxy"
+    },
+    "Server": {
+      "anyOf": [
+        {
+          "$ref": "#/definitions/ServerEnum"
+        },
+        {
+          "$ref": "#/definitions/ServerString"
+        },
+        {
+          "$ref": "#/definitions/ServerObject"
+        }
+      ],
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverserver",
+      "description": "Allows to set server and options (by default 'http')."
+    },
+    "ServerType": {
+      "enum": ["http", "https", "spdy"]
+    },
+    "ServerEnum": {
+      "enum": ["http", "https", "spdy"],
+      "cli": {
+        "exclude": true
+      }
+    },
+    "ServerString": {
+      "type": "string",
+      "minLength": 1,
+      "cli": {
+        "exclude": true
+      }
+    },
+    "ServerObject": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/ServerType"
+            },
+            {
+              "$ref": "#/definitions/ServerString"
+            }
+          ]
+        },
+        "options": {
+          "$ref": "#/definitions/ServerOptions"
+        }
+      },
+      "additionalProperties": false
+    },
+    "ServerOptions": {
+      "type": "object",
+      "additionalProperties": true,
+      "properties": {
+        "passphrase": {
+          "type": "string",
+          "description": "Passphrase for a pfx file."
+        },
+        "requestCert": {
+          "type": "boolean",
+          "description": "Request for an SSL certificate.",
+          "cli": {
+            "negatedDescription": "Does not request for an SSL certificate."
+          }
+        },
+        "ca": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "anyOf": [
+                  {
+                    "type": "string"
+                  },
+                  {
+                    "instanceof": "Buffer"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "string"
+            },
+            {
+              "instanceof": "Buffer"
+            }
+          ],
+          "description": "Path to an SSL CA certificate or content of an SSL CA certificate."
+        },
+        "cacert": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "anyOf": [
+                  {
+                    "type": "string"
+                  },
+                  {
+                    "instanceof": "Buffer"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "string"
+            },
+            {
+              "instanceof": "Buffer"
+            }
+          ],
+          "description": "Path to an SSL CA certificate or content of an SSL CA certificate. Deprecated, use the `server.options.ca` option."
+        },
+        "cert": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "anyOf": [
+                  {
+                    "type": "string"
+                  },
+                  {
+                    "instanceof": "Buffer"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "string"
+            },
+            {
+              "instanceof": "Buffer"
+            }
+          ],
+          "description": "Path to an SSL certificate or content of an SSL certificate."
+        },
+        "crl": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "anyOf": [
+                  {
+                    "type": "string"
+                  },
+                  {
+                    "instanceof": "Buffer"
+                  }
+                ]
+              }
+            },
+            {
+              "type": "string"
+            },
+            {
+              "instanceof": "Buffer"
+            }
+          ],
+          "description": "Path to PEM formatted CRLs (Certificate Revocation Lists) or content of PEM formatted CRLs (Certificate Revocation Lists)."
+        },
+        "key": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "anyOf": [
+                  {
+                    "type": "string"
+                  },
+                  {
+                    "instanceof": "Buffer"
+                  },
+                  {
+                    "type": "object",
+                    "additionalProperties": true
+                  }
+                ]
+              }
+            },
+            {
+              "type": "string"
+            },
+            {
+              "instanceof": "Buffer"
+            }
+          ],
+          "description": "Path to an SSL key or content of an SSL key."
+        },
+        "pfx": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "anyOf": [
+                  {
+                    "type": "string"
+                  },
+                  {
+                    "instanceof": "Buffer"
+                  },
+                  {
+                    "type": "object",
+                    "additionalProperties": true
+                  }
+                ]
+              }
+            },
+            {
+              "type": "string"
+            },
+            {
+              "instanceof": "Buffer"
+            }
+          ],
+          "description": "Path to an SSL pfx file or content of an SSL pfx file."
+        }
+      }
+    },
+    "SetupExitSignals": {
+      "type": "boolean",
+      "description": "Allows to close dev server and exit the process on SIGINT and SIGTERM signals (enabled by default for CLI).",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserversetupexitsignals",
+      "cli": {
+        "exclude": true
+      }
+    },
+    "SetupMiddlewares": {
+      "instanceof": "Function",
+      "description": "Provides the ability to execute a custom function and apply custom middleware(s).",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserversetupmiddlewares"
+    },
+    "Static": {
+      "anyOf": [
+        {
+          "type": "array",
+          "items": {
+            "anyOf": [
+              {
+                "$ref": "#/definitions/StaticString"
+              },
+              {
+                "$ref": "#/definitions/StaticObject"
+              }
+            ]
+          }
+        },
+        {
+          "type": "boolean",
+          "cli": {
+            "negatedDescription": "Disallows to configure options for serving static files from directory."
+          }
+        },
+        {
+          "$ref": "#/definitions/StaticString"
+        },
+        {
+          "$ref": "#/definitions/StaticObject"
+        }
+      ],
+      "description": "Allows to configure options for serving static files from directory (by default 'public' directory).",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverstatic"
+    },
+    "StaticObject": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "directory": {
+          "type": "string",
+          "minLength": 1,
+          "description": "Directory for static contents.",
+          "link": "https://webpack.js.org/configuration/dev-server/#directory"
+        },
+        "staticOptions": {
+          "type": "object",
+          "link": "https://webpack.js.org/configuration/dev-server/#staticoptions",
+          "additionalProperties": true
+        },
+        "publicPath": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "type": "string"
+              },
+              "minItems": 1
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "description": "The static files will be available in the browser under this public path.",
+          "link": "https://webpack.js.org/configuration/dev-server/#publicpath"
+        },
+        "serveIndex": {
+          "anyOf": [
+            {
+              "type": "boolean",
+              "cli": {
+                "negatedDescription": "Does not tell dev server to use serveIndex middleware."
+              }
+            },
+            {
+              "type": "object",
+              "additionalProperties": true
+            }
+          ],
+          "description": "Tells dev server to use serveIndex middleware when enabled.",
+          "link": "https://webpack.js.org/configuration/dev-server/#serveindex"
+        },
+        "watch": {
+          "anyOf": [
+            {
+              "type": "boolean",
+              "cli": {
+                "negatedDescription": "Does not watch for files in static content directory."
+              }
+            },
+            {
+              "type": "object",
+              "description": "Options for watch.",
+              "link": "https://github.com/paulmillr/chokidar#api"
+            }
+          ],
+          "description": "Watches for files in static content directory.",
+          "link": "https://webpack.js.org/configuration/dev-server/#watch"
+        }
+      }
+    },
+    "StaticString": {
+      "type": "string",
+      "minLength": 1
+    },
+    "WatchFiles": {
+      "anyOf": [
+        {
+          "type": "array",
+          "items": {
+            "anyOf": [
+              {
+                "$ref": "#/definitions/WatchFilesString"
+              },
+              {
+                "$ref": "#/definitions/WatchFilesObject"
+              }
+            ]
+          }
+        },
+        {
+          "$ref": "#/definitions/WatchFilesString"
+        },
+        {
+          "$ref": "#/definitions/WatchFilesObject"
+        }
+      ],
+      "description": "Allows to configure list of globs/directories/files to watch for file changes.",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverwatchfiles"
+    },
+    "WatchFilesObject": {
+      "cli": {
+        "exclude": true
+      },
+      "type": "object",
+      "properties": {
+        "paths": {
+          "anyOf": [
+            {
+              "type": "array",
+              "items": {
+                "type": "string",
+                "minLength": 1
+              }
+            },
+            {
+              "type": "string",
+              "minLength": 1
+            }
+          ],
+          "description": "Path(s) of globs/directories/files to watch for file changes."
+        },
+        "options": {
+          "type": "object",
+          "description": "Configure advanced options for watching. See the chokidar documentation for the possible options.",
+          "link": "https://github.com/paulmillr/chokidar#api",
+          "additionalProperties": true
+        }
+      },
+      "additionalProperties": false
+    },
+    "WatchFilesString": {
+      "type": "string",
+      "minLength": 1
+    },
+    "WebSocketServer": {
+      "anyOf": [
+        {
+          "$ref": "#/definitions/WebSocketServerEnum"
+        },
+        {
+          "$ref": "#/definitions/WebSocketServerString"
+        },
+        {
+          "$ref": "#/definitions/WebSocketServerFunction"
+        },
+        {
+          "$ref": "#/definitions/WebSocketServerObject"
+        }
+      ],
+      "description": "Allows to set web socket server and options (by default 'ws').",
+      "link": "https://webpack.js.org/configuration/dev-server/#devserverwebsocketserver"
+    },
+    "WebSocketServerType": {
+      "enum": ["sockjs", "ws"]
+    },
+    "WebSocketServerEnum": {
+      "anyOf": [
+        {
+          "enum": [false],
+          "cli": {
+            "negatedDescription": "Disallows to set web socket server and options."
+          }
+        },
+        {
+          "$ref": "#/definitions/WebSocketServerType"
+        }
+      ],
+      "cli": {
+        "description": "Deprecated: please use '--web-socket-server-type' option."
+      }
+    },
+    "WebSocketServerFunction": {
+      "instanceof": "Function"
+    },
+    "WebSocketServerObject": {
+      "type": "object",
+      "properties": {
+        "type": {
+          "anyOf": [
+            {
+              "$ref": "#/definitions/WebSocketServerType"
+            },
+            {
+              "$ref": "#/definitions/WebSocketServerString"
+            },
+            {
+              "$ref": "#/definitions/WebSocketServerFunction"
+            }
+          ]
+        },
+        "options": {
+          "type": "object",
+          "additionalProperties": true,
+          "cli": {
+            "exclude": true
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "WebSocketServerString": {
+      "type": "string",
+      "minLength": 1
+    }
+  },
+  "additionalProperties": false,
+  "properties": {
+    "allowedHosts": {
+      "$ref": "#/definitions/AllowedHosts"
+    },
+    "bonjour": {
+      "$ref": "#/definitions/Bonjour"
+    },
+    "client": {
+      "$ref": "#/definitions/Client"
+    },
+    "compress": {
+      "$ref": "#/definitions/Compress"
+    },
+    "devMiddleware": {
+      "$ref": "#/definitions/DevMiddleware"
+    },
+    "headers": {
+      "$ref": "#/definitions/Headers"
+    },
+    "historyApiFallback": {
+      "$ref": "#/definitions/HistoryApiFallback"
+    },
+    "host": {
+      "$ref": "#/definitions/Host"
+    },
+    "hot": {
+      "$ref": "#/definitions/Hot"
+    },
+    "http2": {
+      "$ref": "#/definitions/HTTP2"
+    },
+    "https": {
+      "$ref": "#/definitions/HTTPS"
+    },
+    "ipc": {
+      "$ref": "#/definitions/IPC"
+    },
+    "liveReload": {
+      "$ref": "#/definitions/LiveReload"
+    },
+    "magicHtml": {
+      "$ref": "#/definitions/MagicHTML"
+    },
+    "onAfterSetupMiddleware": {
+      "$ref": "#/definitions/OnAfterSetupMiddleware"
+    },
+    "onBeforeSetupMiddleware": {
+      "$ref": "#/definitions/OnBeforeSetupMiddleware"
+    },
+    "onListening": {
+      "$ref": "#/definitions/OnListening"
+    },
+    "open": {
+      "$ref": "#/definitions/Open"
+    },
+    "port": {
+      "$ref": "#/definitions/Port"
+    },
+    "proxy": {
+      "$ref": "#/definitions/Proxy"
+    },
+    "server": {
+      "$ref": "#/definitions/Server"
+    },
+    "setupExitSignals": {
+      "$ref": "#/definitions/SetupExitSignals"
+    },
+    "setupMiddlewares": {
+      "$ref": "#/definitions/SetupMiddlewares"
+    },
+    "static": {
+      "$ref": "#/definitions/Static"
+    },
+    "watchFiles": {
+      "$ref": "#/definitions/WatchFiles"
+    },
+    "webSocketServer": {
+      "$ref": "#/definitions/WebSocketServer"
+    }
+  }
+}
Index: frontend/node_modules/webpack-dev-server/lib/servers/BaseServer.js
===================================================================
--- frontend/node_modules/webpack-dev-server/lib/servers/BaseServer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/lib/servers/BaseServer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+"use strict";
+
+/** @typedef {import("../Server").ClientConnection} ClientConnection */
+
+// base class that users should extend if they are making their own
+// server implementation
+module.exports = class BaseServer {
+  /**
+   * @param {import("../Server")} server
+   */
+  constructor(server) {
+    /** @type {import("../Server")} */
+    this.server = server;
+
+    /** @type {ClientConnection[]} */
+    this.clients = [];
+  }
+};
Index: frontend/node_modules/webpack-dev-server/lib/servers/SockJSServer.js
===================================================================
--- frontend/node_modules/webpack-dev-server/lib/servers/SockJSServer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/lib/servers/SockJSServer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,126 @@
+"use strict";
+
+const sockjs = require("sockjs");
+const BaseServer = require("./BaseServer");
+
+/** @typedef {import("../Server").WebSocketServerConfiguration} WebSocketServerConfiguration */
+/** @typedef {import("../Server").ClientConnection} ClientConnection */
+
+// Workaround for sockjs@~0.3.19
+// sockjs will remove Origin header, however Origin header is required for checking host.
+// See https://github.com/webpack/webpack-dev-server/issues/1604 for more information
+{
+  // @ts-ignore
+  const SockjsSession = require("sockjs/lib/transport").Session;
+  const decorateConnection = SockjsSession.prototype.decorateConnection;
+
+  /**
+   * @param {import("http").IncomingMessage} req
+   */
+  // eslint-disable-next-line func-names
+  SockjsSession.prototype.decorateConnection = function (req) {
+    decorateConnection.call(this, req);
+
+    const connection = this.connection;
+
+    if (
+      connection.headers &&
+      !("origin" in connection.headers) &&
+      "origin" in req.headers
+    ) {
+      connection.headers.origin = req.headers.origin;
+    }
+  };
+}
+
+module.exports = class SockJSServer extends BaseServer {
+  // options has: error (function), debug (function), server (http/s server), path (string)
+  /**
+   * @param {import("../Server")} server
+   */
+  constructor(server) {
+    super(server);
+
+    const webSocketServerOptions =
+      /** @type {NonNullable<WebSocketServerConfiguration["options"]>} */
+      (
+        /** @type {WebSocketServerConfiguration} */
+        (this.server.options.webSocketServer).options
+      );
+
+    /**
+     * @param {NonNullable<WebSocketServerConfiguration["options"]>} options
+     * @returns {string}
+     */
+    const getSockjsUrl = (options) => {
+      if (typeof options.sockjsUrl !== "undefined") {
+        return options.sockjsUrl;
+      }
+
+      return "/__webpack_dev_server__/sockjs.bundle.js";
+    };
+
+    this.implementation = sockjs.createServer({
+      // Use provided up-to-date sockjs-client
+      sockjs_url: getSockjsUrl(webSocketServerOptions),
+      // Default logger is very annoy. Limit useless logs.
+      /**
+       * @param {string} severity
+       * @param {string} line
+       */
+      log: (severity, line) => {
+        if (severity === "error") {
+          this.server.logger.error(line);
+        } else if (severity === "info") {
+          this.server.logger.log(line);
+        } else {
+          this.server.logger.debug(line);
+        }
+      },
+    });
+
+    /**
+     * @param {import("sockjs").ServerOptions & { path?: string }} options
+     * @returns {string | undefined}
+     */
+    const getPrefix = (options) => {
+      if (typeof options.prefix !== "undefined") {
+        return options.prefix;
+      }
+
+      return options.path;
+    };
+
+    const options = {
+      ...webSocketServerOptions,
+      prefix: getPrefix(webSocketServerOptions),
+    };
+
+    this.implementation.installHandlers(
+      /** @type {import("http").Server} */ (this.server.server),
+      options
+    );
+
+    this.implementation.on("connection", (client) => {
+      // @ts-ignore
+      // Implement the the same API as for `ws`
+      client.send = client.write;
+      // @ts-ignore
+      client.terminate = client.close;
+
+      this.clients.push(/** @type {ClientConnection} */ (client));
+
+      client.on("close", () => {
+        this.clients.splice(
+          this.clients.indexOf(/** @type {ClientConnection} */ (client)),
+          1
+        );
+      });
+    });
+
+    // @ts-ignore
+    this.implementation.close = (callback) => {
+      callback();
+    };
+  }
+};
Index: frontend/node_modules/webpack-dev-server/lib/servers/WebsocketServer.js
===================================================================
--- frontend/node_modules/webpack-dev-server/lib/servers/WebsocketServer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/lib/servers/WebsocketServer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,105 @@
+"use strict";
+
+const WebSocket = require("ws");
+const BaseServer = require("./BaseServer");
+
+/** @typedef {import("../Server").WebSocketServerConfiguration} WebSocketServerConfiguration */
+/** @typedef {import("../Server").ClientConnection} ClientConnection */
+
+module.exports = class WebsocketServer extends BaseServer {
+  static heartbeatInterval = 1000;
+
+  /**
+   * @param {import("../Server")} server
+   */
+  constructor(server) {
+    super(server);
+
+    /** @type {import("ws").ServerOptions} */
+    const options = {
+      .../** @type {WebSocketServerConfiguration} */
+      (this.server.options.webSocketServer).options,
+      clientTracking: false,
+    };
+    const isNoServerMode =
+      typeof options.port === "undefined" &&
+      typeof options.server === "undefined";
+
+    if (isNoServerMode) {
+      options.noServer = true;
+    }
+
+    this.implementation = new WebSocket.Server(options);
+
+    /** @type {import("http").Server} */
+    (this.server.server).on(
+      "upgrade",
+      /**
+       * @param {import("http").IncomingMessage} req
+       * @param {import("stream").Duplex} sock
+       * @param {Buffer} head
+       */
+      (req, sock, head) => {
+        if (!this.implementation.shouldHandle(req)) {
+          return;
+        }
+
+        this.implementation.handleUpgrade(req, sock, head, (connection) => {
+          this.implementation.emit("connection", connection, req);
+        });
+      }
+    );
+
+    this.implementation.on(
+      "error",
+      /**
+       * @param {Error} err
+       */
+      (err) => {
+        this.server.logger.error(err.message);
+      }
+    );
+
+    const interval = setInterval(() => {
+      this.clients.forEach(
+        /**
+         * @param {ClientConnection} client
+         */
+        (client) => {
+          if (client.isAlive === false) {
+            client.terminate();
+
+            return;
+          }
+
+          client.isAlive = false;
+          client.ping(() => {});
+        }
+      );
+    }, WebsocketServer.heartbeatInterval);
+
+    this.implementation.on(
+      "connection",
+      /**
+       * @param {ClientConnection} client
+       */
+      (client) => {
+        this.clients.push(client);
+
+        client.isAlive = true;
+
+        client.on("pong", () => {
+          client.isAlive = true;
+        });
+
+        client.on("close", () => {
+          this.clients.splice(this.clients.indexOf(client), 1);
+        });
+      }
+    );
+
+    this.implementation.on("close", () => {
+      clearInterval(interval);
+    });
+  }
+};
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/LICENSE
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+Copyright (c) 2013 Arnout Kazemier and contributors
+Copyright (c) 2016 Luigi Pinca and 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.
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/README.md
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,548 @@
+# ws: a Node.js WebSocket library
+
+[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws)
+[![CI](https://img.shields.io/github/actions/workflow/status/websockets/ws/ci.yml?branch=master&label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster)
+[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws)
+
+ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and
+server implementation.
+
+Passes the quite extensive Autobahn test suite: [server][server-report],
+[client][client-report].
+
+**Note**: This module does not work in the browser. The client in the docs is a
+reference to a backend with the role of a client in the WebSocket communication.
+Browser clients must use the native
+[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
+object. To make the same code work seamlessly on Node.js and the browser, you
+can use one of the many wrappers available on npm, like
+[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
+
+## Table of Contents
+
+- [Protocol support](#protocol-support)
+- [Installing](#installing)
+  - [Opt-in for performance](#opt-in-for-performance)
+    - [Legacy opt-in for performance](#legacy-opt-in-for-performance)
+- [API docs](#api-docs)
+- [WebSocket compression](#websocket-compression)
+- [Usage examples](#usage-examples)
+  - [Sending and receiving text data](#sending-and-receiving-text-data)
+  - [Sending binary data](#sending-binary-data)
+  - [Simple server](#simple-server)
+  - [External HTTP/S server](#external-https-server)
+  - [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server)
+  - [Client authentication](#client-authentication)
+  - [Server broadcast](#server-broadcast)
+  - [Round-trip time](#round-trip-time)
+  - [Use the Node.js streams API](#use-the-nodejs-streams-api)
+  - [Other examples](#other-examples)
+- [FAQ](#faq)
+  - [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
+  - [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
+  - [How to connect via a proxy?](#how-to-connect-via-a-proxy)
+- [Changelog](#changelog)
+- [License](#license)
+
+## Protocol support
+
+- **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
+- **HyBi drafts 13-17** (Current default, alternatively option
+  `protocolVersion: 13`)
+
+## Installing
+
+```
+npm install ws
+```
+
+### Opt-in for performance
+
+[bufferutil][] is an optional module that can be installed alongside the ws
+module:
+
+```
+npm install --save-optional bufferutil
+```
+
+This is a binary addon that improves the performance of certain operations such
+as masking and unmasking the data payload of the WebSocket frames. Prebuilt
+binaries are available for the most popular platforms, so you don't necessarily
+need to have a C++ compiler installed on your machine.
+
+To force ws to not use bufferutil, use the
+[`WS_NO_BUFFER_UTIL`](./doc/ws.md#ws_no_buffer_util) environment variable. This
+can be useful to enhance security in systems where a user can put a package in
+the package search path of an application of another user, due to how the
+Node.js resolver algorithm works.
+
+#### Legacy opt-in for performance
+
+If you are running on an old version of Node.js (prior to v18.14.0), ws also
+supports the [utf-8-validate][] module:
+
+```
+npm install --save-optional utf-8-validate
+```
+
+This contains a binary polyfill for [`buffer.isUtf8()`][].
+
+To force ws not to use utf-8-validate, use the
+[`WS_NO_UTF_8_VALIDATE`](./doc/ws.md#ws_no_utf_8_validate) environment variable.
+
+## API docs
+
+See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and
+utility functions.
+
+## WebSocket compression
+
+ws supports the [permessage-deflate extension][permessage-deflate] which enables
+the client and server to negotiate a compression algorithm and its parameters,
+and then selectively apply it to the data payloads of each WebSocket message.
+
+The extension is disabled by default on the server and enabled by default on the
+client. It adds a significant overhead in terms of performance and memory
+consumption so we suggest to enable it only if it is really needed.
+
+Note that Node.js has a variety of issues with high-performance compression,
+where increased concurrency, especially on Linux, can lead to [catastrophic
+memory fragmentation][node-zlib-bug] and slow performance. If you intend to use
+permessage-deflate in production, it is worthwhile to set up a test
+representative of your workload and ensure Node.js/zlib will handle it with
+acceptable performance and memory usage.
+
+Tuning of permessage-deflate can be done via the options defined below. You can
+also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
+into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
+
+See [the docs][ws-server-options] for more options.
+
+```js
+import WebSocket, { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({
+  port: 8080,
+  perMessageDeflate: {
+    zlibDeflateOptions: {
+      // See zlib defaults.
+      chunkSize: 1024,
+      memLevel: 7,
+      level: 3
+    },
+    zlibInflateOptions: {
+      chunkSize: 10 * 1024
+    },
+    // Other options settable:
+    clientNoContextTakeover: true, // Defaults to negotiated value.
+    serverNoContextTakeover: true, // Defaults to negotiated value.
+    serverMaxWindowBits: 10, // Defaults to negotiated value.
+    // Below options specified as default values.
+    concurrencyLimit: 10, // Limits zlib concurrency for perf.
+    threshold: 1024 // Size (in bytes) below which messages
+    // should not be compressed if context takeover is disabled.
+  }
+});
+```
+
+The client will only use the extension if it is supported and enabled on the
+server. To always disable the extension on the client, set the
+`perMessageDeflate` option to `false`.
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('ws://www.host.com/path', {
+  perMessageDeflate: false
+});
+```
+
+## Usage examples
+
+### Sending and receiving text data
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('ws://www.host.com/path');
+
+ws.on('error', console.error);
+
+ws.on('open', function open() {
+  ws.send('something');
+});
+
+ws.on('message', function message(data) {
+  console.log('received: %s', data);
+});
+```
+
+### Sending binary data
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('ws://www.host.com/path');
+
+ws.on('error', console.error);
+
+ws.on('open', function open() {
+  const array = new Float32Array(5);
+
+  for (var i = 0; i < array.length; ++i) {
+    array[i] = i / 2;
+  }
+
+  ws.send(array);
+});
+```
+
+### Simple server
+
+```js
+import { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+  ws.on('error', console.error);
+
+  ws.on('message', function message(data) {
+    console.log('received: %s', data);
+  });
+
+  ws.send('something');
+});
+```
+
+### External HTTP/S server
+
+```js
+import { createServer } from 'https';
+import { readFileSync } from 'fs';
+import { WebSocketServer } from 'ws';
+
+const server = createServer({
+  cert: readFileSync('/path/to/cert.pem'),
+  key: readFileSync('/path/to/key.pem')
+});
+const wss = new WebSocketServer({ server });
+
+wss.on('connection', function connection(ws) {
+  ws.on('error', console.error);
+
+  ws.on('message', function message(data) {
+    console.log('received: %s', data);
+  });
+
+  ws.send('something');
+});
+
+server.listen(8080);
+```
+
+### Multiple servers sharing a single HTTP/S server
+
+```js
+import { createServer } from 'http';
+import { WebSocketServer } from 'ws';
+
+const server = createServer();
+const wss1 = new WebSocketServer({ noServer: true });
+const wss2 = new WebSocketServer({ noServer: true });
+
+wss1.on('connection', function connection(ws) {
+  ws.on('error', console.error);
+
+  // ...
+});
+
+wss2.on('connection', function connection(ws) {
+  ws.on('error', console.error);
+
+  // ...
+});
+
+server.on('upgrade', function upgrade(request, socket, head) {
+  const { pathname } = new URL(request.url, 'wss://base.url');
+
+  if (pathname === '/foo') {
+    wss1.handleUpgrade(request, socket, head, function done(ws) {
+      wss1.emit('connection', ws, request);
+    });
+  } else if (pathname === '/bar') {
+    wss2.handleUpgrade(request, socket, head, function done(ws) {
+      wss2.emit('connection', ws, request);
+    });
+  } else {
+    socket.destroy();
+  }
+});
+
+server.listen(8080);
+```
+
+### Client authentication
+
+```js
+import { createServer } from 'http';
+import { WebSocketServer } from 'ws';
+
+function onSocketError(err) {
+  console.error(err);
+}
+
+const server = createServer();
+const wss = new WebSocketServer({ noServer: true });
+
+wss.on('connection', function connection(ws, request, client) {
+  ws.on('error', console.error);
+
+  ws.on('message', function message(data) {
+    console.log(`Received message ${data} from user ${client}`);
+  });
+});
+
+server.on('upgrade', function upgrade(request, socket, head) {
+  socket.on('error', onSocketError);
+
+  // This function is not defined on purpose. Implement it with your own logic.
+  authenticate(request, function next(err, client) {
+    if (err || !client) {
+      socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
+      socket.destroy();
+      return;
+    }
+
+    socket.removeListener('error', onSocketError);
+
+    wss.handleUpgrade(request, socket, head, function done(ws) {
+      wss.emit('connection', ws, request, client);
+    });
+  });
+});
+
+server.listen(8080);
+```
+
+Also see the provided [example][session-parse-example] using `express-session`.
+
+### Server broadcast
+
+A client WebSocket broadcasting to all connected WebSocket clients, including
+itself.
+
+```js
+import WebSocket, { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+  ws.on('error', console.error);
+
+  ws.on('message', function message(data, isBinary) {
+    wss.clients.forEach(function each(client) {
+      if (client.readyState === WebSocket.OPEN) {
+        client.send(data, { binary: isBinary });
+      }
+    });
+  });
+});
+```
+
+A client WebSocket broadcasting to every other connected WebSocket clients,
+excluding itself.
+
+```js
+import WebSocket, { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+  ws.on('error', console.error);
+
+  ws.on('message', function message(data, isBinary) {
+    wss.clients.forEach(function each(client) {
+      if (client !== ws && client.readyState === WebSocket.OPEN) {
+        client.send(data, { binary: isBinary });
+      }
+    });
+  });
+});
+```
+
+### Round-trip time
+
+```js
+import WebSocket from 'ws';
+
+const ws = new WebSocket('wss://websocket-echo.com/');
+
+ws.on('error', console.error);
+
+ws.on('open', function open() {
+  console.log('connected');
+  ws.send(Date.now());
+});
+
+ws.on('close', function close() {
+  console.log('disconnected');
+});
+
+ws.on('message', function message(data) {
+  console.log(`Round-trip time: ${Date.now() - data} ms`);
+
+  setTimeout(function timeout() {
+    ws.send(Date.now());
+  }, 500);
+});
+```
+
+### Use the Node.js streams API
+
+```js
+import WebSocket, { createWebSocketStream } from 'ws';
+
+const ws = new WebSocket('wss://websocket-echo.com/');
+
+const duplex = createWebSocketStream(ws, { encoding: 'utf8' });
+
+duplex.on('error', console.error);
+
+duplex.pipe(process.stdout);
+process.stdin.pipe(duplex);
+```
+
+### Other examples
+
+For a full example with a browser client communicating with a ws server, see the
+examples folder.
+
+Otherwise, see the test cases.
+
+## FAQ
+
+### How to get the IP address of the client?
+
+The remote IP address can be obtained from the raw socket.
+
+```js
+import { WebSocketServer } from 'ws';
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws, req) {
+  const ip = req.socket.remoteAddress;
+
+  ws.on('error', console.error);
+});
+```
+
+When the server runs behind a proxy like NGINX, the de-facto standard is to use
+the `X-Forwarded-For` header.
+
+```js
+wss.on('connection', function connection(ws, req) {
+  const ip = req.headers['x-forwarded-for'].split(',')[0].trim();
+
+  ws.on('error', console.error);
+});
+```
+
+### How to detect and close broken connections?
+
+Sometimes, the link between the server and the client can be interrupted in a
+way that keeps both the server and the client unaware of the broken state of the
+connection (e.g. when pulling the cord).
+
+In these cases, ping messages can be used as a means to verify that the remote
+endpoint is still responsive.
+
+```js
+import { WebSocketServer } from 'ws';
+
+function heartbeat() {
+  this.isAlive = true;
+}
+
+const wss = new WebSocketServer({ port: 8080 });
+
+wss.on('connection', function connection(ws) {
+  ws.isAlive = true;
+  ws.on('error', console.error);
+  ws.on('pong', heartbeat);
+});
+
+const interval = setInterval(function ping() {
+  wss.clients.forEach(function each(ws) {
+    if (ws.isAlive === false) return ws.terminate();
+
+    ws.isAlive = false;
+    ws.ping();
+  });
+}, 30000);
+
+wss.on('close', function close() {
+  clearInterval(interval);
+});
+```
+
+Pong messages are automatically sent in response to ping messages as required by
+the spec.
+
+Just like the server example above, your clients might as well lose connection
+without knowing it. You might want to add a ping listener on your clients to
+prevent that. A simple implementation would be:
+
+```js
+import WebSocket from 'ws';
+
+function heartbeat() {
+  clearTimeout(this.pingTimeout);
+
+  // Use `WebSocket#terminate()`, which immediately destroys the connection,
+  // instead of `WebSocket#close()`, which waits for the close timer.
+  // Delay should be equal to the interval at which your server
+  // sends out pings plus a conservative assumption of the latency.
+  this.pingTimeout = setTimeout(() => {
+    this.terminate();
+  }, 30000 + 1000);
+}
+
+const client = new WebSocket('wss://websocket-echo.com/');
+
+client.on('error', console.error);
+client.on('open', heartbeat);
+client.on('ping', heartbeat);
+client.on('close', function clear() {
+  clearTimeout(this.pingTimeout);
+});
+```
+
+### How to connect via a proxy?
+
+Use a custom `http.Agent` implementation like [https-proxy-agent][] or
+[socks-proxy-agent][].
+
+## Changelog
+
+We're using the GitHub [releases][changelog] for changelog entries.
+
+## License
+
+[MIT](LICENSE)
+
+[`buffer.isutf8()`]: https://nodejs.org/api/buffer.html#bufferisutf8input
+[bufferutil]: https://github.com/websockets/bufferutil
+[changelog]: https://github.com/websockets/ws/releases
+[client-report]: http://websockets.github.io/ws/autobahn/clients/
+[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
+[node-zlib-bug]: https://github.com/nodejs/node/issues/8871
+[node-zlib-deflaterawdocs]:
+  https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
+[permessage-deflate]: https://tools.ietf.org/html/rfc7692
+[server-report]: http://websockets.github.io/ws/autobahn/servers/
+[session-parse-example]: ./examples/express-session-parse
+[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
+[utf-8-validate]: https://github.com/websockets/utf-8-validate
+[ws-server-options]: ./doc/ws.md#new-websocketserveroptions-callback
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/browser.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/browser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/browser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+'use strict';
+
+module.exports = function () {
+  throw new Error(
+    'ws does not work in the browser. Browser clients must use the native ' +
+      'WebSocket object'
+  );
+};
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/index.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+'use strict';
+
+const createWebSocketStream = require('./lib/stream');
+const extension = require('./lib/extension');
+const PerMessageDeflate = require('./lib/permessage-deflate');
+const Receiver = require('./lib/receiver');
+const Sender = require('./lib/sender');
+const subprotocol = require('./lib/subprotocol');
+const WebSocket = require('./lib/websocket');
+const WebSocketServer = require('./lib/websocket-server');
+
+WebSocket.createWebSocketStream = createWebSocketStream;
+WebSocket.extension = extension;
+WebSocket.PerMessageDeflate = PerMessageDeflate;
+WebSocket.Receiver = Receiver;
+WebSocket.Sender = Sender;
+WebSocket.Server = WebSocketServer;
+WebSocket.subprotocol = subprotocol;
+WebSocket.WebSocket = WebSocket;
+WebSocket.WebSocketServer = WebSocketServer;
+
+module.exports = WebSocket;
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/buffer-util.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/buffer-util.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/buffer-util.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,131 @@
+'use strict';
+
+const { EMPTY_BUFFER } = require('./constants');
+
+const FastBuffer = Buffer[Symbol.species];
+
+/**
+ * Merges an array of buffers into a new buffer.
+ *
+ * @param {Buffer[]} list The array of buffers to concat
+ * @param {Number} totalLength The total length of buffers in the list
+ * @return {Buffer} The resulting buffer
+ * @public
+ */
+function concat(list, totalLength) {
+  if (list.length === 0) return EMPTY_BUFFER;
+  if (list.length === 1) return list[0];
+
+  const target = Buffer.allocUnsafe(totalLength);
+  let offset = 0;
+
+  for (let i = 0; i < list.length; i++) {
+    const buf = list[i];
+    target.set(buf, offset);
+    offset += buf.length;
+  }
+
+  if (offset < totalLength) {
+    return new FastBuffer(target.buffer, target.byteOffset, offset);
+  }
+
+  return target;
+}
+
+/**
+ * Masks a buffer using the given mask.
+ *
+ * @param {Buffer} source The buffer to mask
+ * @param {Buffer} mask The mask to use
+ * @param {Buffer} output The buffer where to store the result
+ * @param {Number} offset The offset at which to start writing
+ * @param {Number} length The number of bytes to mask.
+ * @public
+ */
+function _mask(source, mask, output, offset, length) {
+  for (let i = 0; i < length; i++) {
+    output[offset + i] = source[i] ^ mask[i & 3];
+  }
+}
+
+/**
+ * Unmasks a buffer using the given mask.
+ *
+ * @param {Buffer} buffer The buffer to unmask
+ * @param {Buffer} mask The mask to use
+ * @public
+ */
+function _unmask(buffer, mask) {
+  for (let i = 0; i < buffer.length; i++) {
+    buffer[i] ^= mask[i & 3];
+  }
+}
+
+/**
+ * Converts a buffer to an `ArrayBuffer`.
+ *
+ * @param {Buffer} buf The buffer to convert
+ * @return {ArrayBuffer} Converted buffer
+ * @public
+ */
+function toArrayBuffer(buf) {
+  if (buf.length === buf.buffer.byteLength) {
+    return buf.buffer;
+  }
+
+  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
+}
+
+/**
+ * Converts `data` to a `Buffer`.
+ *
+ * @param {*} data The data to convert
+ * @return {Buffer} The buffer
+ * @throws {TypeError}
+ * @public
+ */
+function toBuffer(data) {
+  toBuffer.readOnly = true;
+
+  if (Buffer.isBuffer(data)) return data;
+
+  let buf;
+
+  if (data instanceof ArrayBuffer) {
+    buf = new FastBuffer(data);
+  } else if (ArrayBuffer.isView(data)) {
+    buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);
+  } else {
+    buf = Buffer.from(data);
+    toBuffer.readOnly = false;
+  }
+
+  return buf;
+}
+
+module.exports = {
+  concat,
+  mask: _mask,
+  toArrayBuffer,
+  toBuffer,
+  unmask: _unmask
+};
+
+/* istanbul ignore else  */
+if (!process.env.WS_NO_BUFFER_UTIL) {
+  try {
+    const bufferUtil = require('bufferutil');
+
+    module.exports.mask = function (source, mask, output, offset, length) {
+      if (length < 48) _mask(source, mask, output, offset, length);
+      else bufferUtil.mask(source, mask, output, offset, length);
+    };
+
+    module.exports.unmask = function (buffer, mask) {
+      if (buffer.length < 32) _unmask(buffer, mask);
+      else bufferUtil.unmask(buffer, mask);
+    };
+  } catch (e) {
+    // Continue regardless of the error.
+  }
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/constants.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/constants.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/constants.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,19 @@
+'use strict';
+
+const BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];
+const hasBlob = typeof Blob !== 'undefined';
+
+if (hasBlob) BINARY_TYPES.push('blob');
+
+module.exports = {
+  BINARY_TYPES,
+  CLOSE_TIMEOUT: 30000,
+  EMPTY_BUFFER: Buffer.alloc(0),
+  GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
+  hasBlob,
+  kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),
+  kListener: Symbol('kListener'),
+  kStatusCode: Symbol('status-code'),
+  kWebSocket: Symbol('websocket'),
+  NOOP: () => {}
+};
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/event-target.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/event-target.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/event-target.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,292 @@
+'use strict';
+
+const { kForOnEventAttribute, kListener } = require('./constants');
+
+const kCode = Symbol('kCode');
+const kData = Symbol('kData');
+const kError = Symbol('kError');
+const kMessage = Symbol('kMessage');
+const kReason = Symbol('kReason');
+const kTarget = Symbol('kTarget');
+const kType = Symbol('kType');
+const kWasClean = Symbol('kWasClean');
+
+/**
+ * Class representing an event.
+ */
+class Event {
+  /**
+   * Create a new `Event`.
+   *
+   * @param {String} type The name of the event
+   * @throws {TypeError} If the `type` argument is not specified
+   */
+  constructor(type) {
+    this[kTarget] = null;
+    this[kType] = type;
+  }
+
+  /**
+   * @type {*}
+   */
+  get target() {
+    return this[kTarget];
+  }
+
+  /**
+   * @type {String}
+   */
+  get type() {
+    return this[kType];
+  }
+}
+
+Object.defineProperty(Event.prototype, 'target', { enumerable: true });
+Object.defineProperty(Event.prototype, 'type', { enumerable: true });
+
+/**
+ * Class representing a close event.
+ *
+ * @extends Event
+ */
+class CloseEvent extends Event {
+  /**
+   * Create a new `CloseEvent`.
+   *
+   * @param {String} type The name of the event
+   * @param {Object} [options] A dictionary object that allows for setting
+   *     attributes via object members of the same name
+   * @param {Number} [options.code=0] The status code explaining why the
+   *     connection was closed
+   * @param {String} [options.reason=''] A human-readable string explaining why
+   *     the connection was closed
+   * @param {Boolean} [options.wasClean=false] Indicates whether or not the
+   *     connection was cleanly closed
+   */
+  constructor(type, options = {}) {
+    super(type);
+
+    this[kCode] = options.code === undefined ? 0 : options.code;
+    this[kReason] = options.reason === undefined ? '' : options.reason;
+    this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;
+  }
+
+  /**
+   * @type {Number}
+   */
+  get code() {
+    return this[kCode];
+  }
+
+  /**
+   * @type {String}
+   */
+  get reason() {
+    return this[kReason];
+  }
+
+  /**
+   * @type {Boolean}
+   */
+  get wasClean() {
+    return this[kWasClean];
+  }
+}
+
+Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });
+Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });
+Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });
+
+/**
+ * Class representing an error event.
+ *
+ * @extends Event
+ */
+class ErrorEvent extends Event {
+  /**
+   * Create a new `ErrorEvent`.
+   *
+   * @param {String} type The name of the event
+   * @param {Object} [options] A dictionary object that allows for setting
+   *     attributes via object members of the same name
+   * @param {*} [options.error=null] The error that generated this event
+   * @param {String} [options.message=''] The error message
+   */
+  constructor(type, options = {}) {
+    super(type);
+
+    this[kError] = options.error === undefined ? null : options.error;
+    this[kMessage] = options.message === undefined ? '' : options.message;
+  }
+
+  /**
+   * @type {*}
+   */
+  get error() {
+    return this[kError];
+  }
+
+  /**
+   * @type {String}
+   */
+  get message() {
+    return this[kMessage];
+  }
+}
+
+Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });
+Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });
+
+/**
+ * Class representing a message event.
+ *
+ * @extends Event
+ */
+class MessageEvent extends Event {
+  /**
+   * Create a new `MessageEvent`.
+   *
+   * @param {String} type The name of the event
+   * @param {Object} [options] A dictionary object that allows for setting
+   *     attributes via object members of the same name
+   * @param {*} [options.data=null] The message content
+   */
+  constructor(type, options = {}) {
+    super(type);
+
+    this[kData] = options.data === undefined ? null : options.data;
+  }
+
+  /**
+   * @type {*}
+   */
+  get data() {
+    return this[kData];
+  }
+}
+
+Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });
+
+/**
+ * This provides methods for emulating the `EventTarget` interface. It's not
+ * meant to be used directly.
+ *
+ * @mixin
+ */
+const EventTarget = {
+  /**
+   * Register an event listener.
+   *
+   * @param {String} type A string representing the event type to listen for
+   * @param {(Function|Object)} handler The listener to add
+   * @param {Object} [options] An options object specifies characteristics about
+   *     the event listener
+   * @param {Boolean} [options.once=false] A `Boolean` indicating that the
+   *     listener should be invoked at most once after being added. If `true`,
+   *     the listener would be automatically removed when invoked.
+   * @public
+   */
+  addEventListener(type, handler, options = {}) {
+    for (const listener of this.listeners(type)) {
+      if (
+        !options[kForOnEventAttribute] &&
+        listener[kListener] === handler &&
+        !listener[kForOnEventAttribute]
+      ) {
+        return;
+      }
+    }
+
+    let wrapper;
+
+    if (type === 'message') {
+      wrapper = function onMessage(data, isBinary) {
+        const event = new MessageEvent('message', {
+          data: isBinary ? data : data.toString()
+        });
+
+        event[kTarget] = this;
+        callListener(handler, this, event);
+      };
+    } else if (type === 'close') {
+      wrapper = function onClose(code, message) {
+        const event = new CloseEvent('close', {
+          code,
+          reason: message.toString(),
+          wasClean: this._closeFrameReceived && this._closeFrameSent
+        });
+
+        event[kTarget] = this;
+        callListener(handler, this, event);
+      };
+    } else if (type === 'error') {
+      wrapper = function onError(error) {
+        const event = new ErrorEvent('error', {
+          error,
+          message: error.message
+        });
+
+        event[kTarget] = this;
+        callListener(handler, this, event);
+      };
+    } else if (type === 'open') {
+      wrapper = function onOpen() {
+        const event = new Event('open');
+
+        event[kTarget] = this;
+        callListener(handler, this, event);
+      };
+    } else {
+      return;
+    }
+
+    wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
+    wrapper[kListener] = handler;
+
+    if (options.once) {
+      this.once(type, wrapper);
+    } else {
+      this.on(type, wrapper);
+    }
+  },
+
+  /**
+   * Remove an event listener.
+   *
+   * @param {String} type A string representing the event type to remove
+   * @param {(Function|Object)} handler The listener to remove
+   * @public
+   */
+  removeEventListener(type, handler) {
+    for (const listener of this.listeners(type)) {
+      if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
+        this.removeListener(type, listener);
+        break;
+      }
+    }
+  }
+};
+
+module.exports = {
+  CloseEvent,
+  ErrorEvent,
+  Event,
+  EventTarget,
+  MessageEvent
+};
+
+/**
+ * Call an event listener
+ *
+ * @param {(Function|Object)} listener The listener to call
+ * @param {*} thisArg The value to use as `this`` when calling the listener
+ * @param {Event} event The event to pass to the listener
+ * @private
+ */
+function callListener(listener, thisArg, event) {
+  if (typeof listener === 'object' && listener.handleEvent) {
+    listener.handleEvent.call(listener, event);
+  } else {
+    listener.call(thisArg, event);
+  }
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/extension.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/extension.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/extension.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,203 @@
+'use strict';
+
+const { tokenChars } = require('./validation');
+
+/**
+ * Adds an offer to the map of extension offers or a parameter to the map of
+ * parameters.
+ *
+ * @param {Object} dest The map of extension offers or parameters
+ * @param {String} name The extension or parameter name
+ * @param {(Object|Boolean|String)} elem The extension parameters or the
+ *     parameter value
+ * @private
+ */
+function push(dest, name, elem) {
+  if (dest[name] === undefined) dest[name] = [elem];
+  else dest[name].push(elem);
+}
+
+/**
+ * Parses the `Sec-WebSocket-Extensions` header into an object.
+ *
+ * @param {String} header The field value of the header
+ * @return {Object} The parsed object
+ * @public
+ */
+function parse(header) {
+  const offers = Object.create(null);
+  let params = Object.create(null);
+  let mustUnescape = false;
+  let isEscaping = false;
+  let inQuotes = false;
+  let extensionName;
+  let paramName;
+  let start = -1;
+  let code = -1;
+  let end = -1;
+  let i = 0;
+
+  for (; i < header.length; i++) {
+    code = header.charCodeAt(i);
+
+    if (extensionName === undefined) {
+      if (end === -1 && tokenChars[code] === 1) {
+        if (start === -1) start = i;
+      } else if (
+        i !== 0 &&
+        (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
+      ) {
+        if (end === -1 && start !== -1) end = i;
+      } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
+        if (start === -1) {
+          throw new SyntaxError(`Unexpected character at index ${i}`);
+        }
+
+        if (end === -1) end = i;
+        const name = header.slice(start, end);
+        if (code === 0x2c) {
+          push(offers, name, params);
+          params = Object.create(null);
+        } else {
+          extensionName = name;
+        }
+
+        start = end = -1;
+      } else {
+        throw new SyntaxError(`Unexpected character at index ${i}`);
+      }
+    } else if (paramName === undefined) {
+      if (end === -1 && tokenChars[code] === 1) {
+        if (start === -1) start = i;
+      } else if (code === 0x20 || code === 0x09) {
+        if (end === -1 && start !== -1) end = i;
+      } else if (code === 0x3b || code === 0x2c) {
+        if (start === -1) {
+          throw new SyntaxError(`Unexpected character at index ${i}`);
+        }
+
+        if (end === -1) end = i;
+        push(params, header.slice(start, end), true);
+        if (code === 0x2c) {
+          push(offers, extensionName, params);
+          params = Object.create(null);
+          extensionName = undefined;
+        }
+
+        start = end = -1;
+      } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
+        paramName = header.slice(start, i);
+        start = end = -1;
+      } else {
+        throw new SyntaxError(`Unexpected character at index ${i}`);
+      }
+    } else {
+      //
+      // The value of a quoted-string after unescaping must conform to the
+      // token ABNF, so only token characters are valid.
+      // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
+      //
+      if (isEscaping) {
+        if (tokenChars[code] !== 1) {
+          throw new SyntaxError(`Unexpected character at index ${i}`);
+        }
+        if (start === -1) start = i;
+        else if (!mustUnescape) mustUnescape = true;
+        isEscaping = false;
+      } else if (inQuotes) {
+        if (tokenChars[code] === 1) {
+          if (start === -1) start = i;
+        } else if (code === 0x22 /* '"' */ && start !== -1) {
+          inQuotes = false;
+          end = i;
+        } else if (code === 0x5c /* '\' */) {
+          isEscaping = true;
+        } else {
+          throw new SyntaxError(`Unexpected character at index ${i}`);
+        }
+      } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
+        inQuotes = true;
+      } else if (end === -1 && tokenChars[code] === 1) {
+        if (start === -1) start = i;
+      } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
+        if (end === -1) end = i;
+      } else if (code === 0x3b || code === 0x2c) {
+        if (start === -1) {
+          throw new SyntaxError(`Unexpected character at index ${i}`);
+        }
+
+        if (end === -1) end = i;
+        let value = header.slice(start, end);
+        if (mustUnescape) {
+          value = value.replace(/\\/g, '');
+          mustUnescape = false;
+        }
+        push(params, paramName, value);
+        if (code === 0x2c) {
+          push(offers, extensionName, params);
+          params = Object.create(null);
+          extensionName = undefined;
+        }
+
+        paramName = undefined;
+        start = end = -1;
+      } else {
+        throw new SyntaxError(`Unexpected character at index ${i}`);
+      }
+    }
+  }
+
+  if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {
+    throw new SyntaxError('Unexpected end of input');
+  }
+
+  if (end === -1) end = i;
+  const token = header.slice(start, end);
+  if (extensionName === undefined) {
+    push(offers, token, params);
+  } else {
+    if (paramName === undefined) {
+      push(params, token, true);
+    } else if (mustUnescape) {
+      push(params, paramName, token.replace(/\\/g, ''));
+    } else {
+      push(params, paramName, token);
+    }
+    push(offers, extensionName, params);
+  }
+
+  return offers;
+}
+
+/**
+ * Builds the `Sec-WebSocket-Extensions` header field value.
+ *
+ * @param {Object} extensions The map of extensions and parameters to format
+ * @return {String} A string representing the given object
+ * @public
+ */
+function format(extensions) {
+  return Object.keys(extensions)
+    .map((extension) => {
+      let configurations = extensions[extension];
+      if (!Array.isArray(configurations)) configurations = [configurations];
+      return configurations
+        .map((params) => {
+          return [extension]
+            .concat(
+              Object.keys(params).map((k) => {
+                let values = params[k];
+                if (!Array.isArray(values)) values = [values];
+                return values
+                  .map((v) => (v === true ? k : `${k}=${v}`))
+                  .join('; ');
+              })
+            )
+            .join('; ');
+        })
+        .join(', ');
+    })
+    .join(', ');
+}
+
+module.exports = { format, parse };
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/limiter.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/limiter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/limiter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+'use strict';
+
+const kDone = Symbol('kDone');
+const kRun = Symbol('kRun');
+
+/**
+ * A very simple job queue with adjustable concurrency. Adapted from
+ * https://github.com/STRML/async-limiter
+ */
+class Limiter {
+  /**
+   * Creates a new `Limiter`.
+   *
+   * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
+   *     to run concurrently
+   */
+  constructor(concurrency) {
+    this[kDone] = () => {
+      this.pending--;
+      this[kRun]();
+    };
+    this.concurrency = concurrency || Infinity;
+    this.jobs = [];
+    this.pending = 0;
+  }
+
+  /**
+   * Adds a job to the queue.
+   *
+   * @param {Function} job The job to run
+   * @public
+   */
+  add(job) {
+    this.jobs.push(job);
+    this[kRun]();
+  }
+
+  /**
+   * Removes a job from the queue and runs it if possible.
+   *
+   * @private
+   */
+  [kRun]() {
+    if (this.pending === this.concurrency) return;
+
+    if (this.jobs.length) {
+      const job = this.jobs.shift();
+
+      this.pending++;
+      job(this[kDone]);
+    }
+  }
+}
+
+module.exports = Limiter;
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/permessage-deflate.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/permessage-deflate.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/permessage-deflate.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,528 @@
+'use strict';
+
+const zlib = require('zlib');
+
+const bufferUtil = require('./buffer-util');
+const Limiter = require('./limiter');
+const { kStatusCode } = require('./constants');
+
+const FastBuffer = Buffer[Symbol.species];
+const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
+const kPerMessageDeflate = Symbol('permessage-deflate');
+const kTotalLength = Symbol('total-length');
+const kCallback = Symbol('callback');
+const kBuffers = Symbol('buffers');
+const kError = Symbol('error');
+
+//
+// We limit zlib concurrency, which prevents severe memory fragmentation
+// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
+// and https://github.com/websockets/ws/issues/1202
+//
+// Intentionally global; it's the global thread pool that's an issue.
+//
+let zlibLimiter;
+
+/**
+ * permessage-deflate implementation.
+ */
+class PerMessageDeflate {
+  /**
+   * Creates a PerMessageDeflate instance.
+   *
+   * @param {Object} [options] Configuration options
+   * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
+   *     for, or request, a custom client window size
+   * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
+   *     acknowledge disabling of client context takeover
+   * @param {Number} [options.concurrencyLimit=10] The number of concurrent
+   *     calls to zlib
+   * @param {Boolean} [options.isServer=false] Create the instance in either
+   *     server or client mode
+   * @param {Number} [options.maxPayload=0] The maximum allowed message length
+   * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
+   *     use of a custom server window size
+   * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
+   *     disabling of server context takeover
+   * @param {Number} [options.threshold=1024] Size (in bytes) below which
+   *     messages should not be compressed if context takeover is disabled
+   * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
+   *     deflate
+   * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
+   *     inflate
+   */
+  constructor(options) {
+    this._options = options || {};
+    this._threshold =
+      this._options.threshold !== undefined ? this._options.threshold : 1024;
+    this._maxPayload = this._options.maxPayload | 0;
+    this._isServer = !!this._options.isServer;
+    this._deflate = null;
+    this._inflate = null;
+
+    this.params = null;
+
+    if (!zlibLimiter) {
+      const concurrency =
+        this._options.concurrencyLimit !== undefined
+          ? this._options.concurrencyLimit
+          : 10;
+      zlibLimiter = new Limiter(concurrency);
+    }
+  }
+
+  /**
+   * @type {String}
+   */
+  static get extensionName() {
+    return 'permessage-deflate';
+  }
+
+  /**
+   * Create an extension negotiation offer.
+   *
+   * @return {Object} Extension parameters
+   * @public
+   */
+  offer() {
+    const params = {};
+
+    if (this._options.serverNoContextTakeover) {
+      params.server_no_context_takeover = true;
+    }
+    if (this._options.clientNoContextTakeover) {
+      params.client_no_context_takeover = true;
+    }
+    if (this._options.serverMaxWindowBits) {
+      params.server_max_window_bits = this._options.serverMaxWindowBits;
+    }
+    if (this._options.clientMaxWindowBits) {
+      params.client_max_window_bits = this._options.clientMaxWindowBits;
+    } else if (this._options.clientMaxWindowBits == null) {
+      params.client_max_window_bits = true;
+    }
+
+    return params;
+  }
+
+  /**
+   * Accept an extension negotiation offer/response.
+   *
+   * @param {Array} configurations The extension negotiation offers/reponse
+   * @return {Object} Accepted configuration
+   * @public
+   */
+  accept(configurations) {
+    configurations = this.normalizeParams(configurations);
+
+    this.params = this._isServer
+      ? this.acceptAsServer(configurations)
+      : this.acceptAsClient(configurations);
+
+    return this.params;
+  }
+
+  /**
+   * Releases all resources used by the extension.
+   *
+   * @public
+   */
+  cleanup() {
+    if (this._inflate) {
+      this._inflate.close();
+      this._inflate = null;
+    }
+
+    if (this._deflate) {
+      const callback = this._deflate[kCallback];
+
+      this._deflate.close();
+      this._deflate = null;
+
+      if (callback) {
+        callback(
+          new Error(
+            'The deflate stream was closed while data was being processed'
+          )
+        );
+      }
+    }
+  }
+
+  /**
+   *  Accept an extension negotiation offer.
+   *
+   * @param {Array} offers The extension negotiation offers
+   * @return {Object} Accepted configuration
+   * @private
+   */
+  acceptAsServer(offers) {
+    const opts = this._options;
+    const accepted = offers.find((params) => {
+      if (
+        (opts.serverNoContextTakeover === false &&
+          params.server_no_context_takeover) ||
+        (params.server_max_window_bits &&
+          (opts.serverMaxWindowBits === false ||
+            (typeof opts.serverMaxWindowBits === 'number' &&
+              opts.serverMaxWindowBits > params.server_max_window_bits))) ||
+        (typeof opts.clientMaxWindowBits === 'number' &&
+          !params.client_max_window_bits)
+      ) {
+        return false;
+      }
+
+      return true;
+    });
+
+    if (!accepted) {
+      throw new Error('None of the extension offers can be accepted');
+    }
+
+    if (opts.serverNoContextTakeover) {
+      accepted.server_no_context_takeover = true;
+    }
+    if (opts.clientNoContextTakeover) {
+      accepted.client_no_context_takeover = true;
+    }
+    if (typeof opts.serverMaxWindowBits === 'number') {
+      accepted.server_max_window_bits = opts.serverMaxWindowBits;
+    }
+    if (typeof opts.clientMaxWindowBits === 'number') {
+      accepted.client_max_window_bits = opts.clientMaxWindowBits;
+    } else if (
+      accepted.client_max_window_bits === true ||
+      opts.clientMaxWindowBits === false
+    ) {
+      delete accepted.client_max_window_bits;
+    }
+
+    return accepted;
+  }
+
+  /**
+   * Accept the extension negotiation response.
+   *
+   * @param {Array} response The extension negotiation response
+   * @return {Object} Accepted configuration
+   * @private
+   */
+  acceptAsClient(response) {
+    const params = response[0];
+
+    if (
+      this._options.clientNoContextTakeover === false &&
+      params.client_no_context_takeover
+    ) {
+      throw new Error('Unexpected parameter "client_no_context_takeover"');
+    }
+
+    if (!params.client_max_window_bits) {
+      if (typeof this._options.clientMaxWindowBits === 'number') {
+        params.client_max_window_bits = this._options.clientMaxWindowBits;
+      }
+    } else if (
+      this._options.clientMaxWindowBits === false ||
+      (typeof this._options.clientMaxWindowBits === 'number' &&
+        params.client_max_window_bits > this._options.clientMaxWindowBits)
+    ) {
+      throw new Error(
+        'Unexpected or invalid parameter "client_max_window_bits"'
+      );
+    }
+
+    return params;
+  }
+
+  /**
+   * Normalize parameters.
+   *
+   * @param {Array} configurations The extension negotiation offers/reponse
+   * @return {Array} The offers/response with normalized parameters
+   * @private
+   */
+  normalizeParams(configurations) {
+    configurations.forEach((params) => {
+      Object.keys(params).forEach((key) => {
+        let value = params[key];
+
+        if (value.length > 1) {
+          throw new Error(`Parameter "${key}" must have only a single value`);
+        }
+
+        value = value[0];
+
+        if (key === 'client_max_window_bits') {
+          if (value !== true) {
+            const num = +value;
+            if (!Number.isInteger(num) || num < 8 || num > 15) {
+              throw new TypeError(
+                `Invalid value for parameter "${key}": ${value}`
+              );
+            }
+            value = num;
+          } else if (!this._isServer) {
+            throw new TypeError(
+              `Invalid value for parameter "${key}": ${value}`
+            );
+          }
+        } else if (key === 'server_max_window_bits') {
+          const num = +value;
+          if (!Number.isInteger(num) || num < 8 || num > 15) {
+            throw new TypeError(
+              `Invalid value for parameter "${key}": ${value}`
+            );
+          }
+          value = num;
+        } else if (
+          key === 'client_no_context_takeover' ||
+          key === 'server_no_context_takeover'
+        ) {
+          if (value !== true) {
+            throw new TypeError(
+              `Invalid value for parameter "${key}": ${value}`
+            );
+          }
+        } else {
+          throw new Error(`Unknown parameter "${key}"`);
+        }
+
+        params[key] = value;
+      });
+    });
+
+    return configurations;
+  }
+
+  /**
+   * Decompress data. Concurrency limited.
+   *
+   * @param {Buffer} data Compressed data
+   * @param {Boolean} fin Specifies whether or not this is the last fragment
+   * @param {Function} callback Callback
+   * @public
+   */
+  decompress(data, fin, callback) {
+    zlibLimiter.add((done) => {
+      this._decompress(data, fin, (err, result) => {
+        done();
+        callback(err, result);
+      });
+    });
+  }
+
+  /**
+   * Compress data. Concurrency limited.
+   *
+   * @param {(Buffer|String)} data Data to compress
+   * @param {Boolean} fin Specifies whether or not this is the last fragment
+   * @param {Function} callback Callback
+   * @public
+   */
+  compress(data, fin, callback) {
+    zlibLimiter.add((done) => {
+      this._compress(data, fin, (err, result) => {
+        done();
+        callback(err, result);
+      });
+    });
+  }
+
+  /**
+   * Decompress data.
+   *
+   * @param {Buffer} data Compressed data
+   * @param {Boolean} fin Specifies whether or not this is the last fragment
+   * @param {Function} callback Callback
+   * @private
+   */
+  _decompress(data, fin, callback) {
+    const endpoint = this._isServer ? 'client' : 'server';
+
+    if (!this._inflate) {
+      const key = `${endpoint}_max_window_bits`;
+      const windowBits =
+        typeof this.params[key] !== 'number'
+          ? zlib.Z_DEFAULT_WINDOWBITS
+          : this.params[key];
+
+      this._inflate = zlib.createInflateRaw({
+        ...this._options.zlibInflateOptions,
+        windowBits
+      });
+      this._inflate[kPerMessageDeflate] = this;
+      this._inflate[kTotalLength] = 0;
+      this._inflate[kBuffers] = [];
+      this._inflate.on('error', inflateOnError);
+      this._inflate.on('data', inflateOnData);
+    }
+
+    this._inflate[kCallback] = callback;
+
+    this._inflate.write(data);
+    if (fin) this._inflate.write(TRAILER);
+
+    this._inflate.flush(() => {
+      const err = this._inflate[kError];
+
+      if (err) {
+        this._inflate.close();
+        this._inflate = null;
+        callback(err);
+        return;
+      }
+
+      const data = bufferUtil.concat(
+        this._inflate[kBuffers],
+        this._inflate[kTotalLength]
+      );
+
+      if (this._inflate._readableState.endEmitted) {
+        this._inflate.close();
+        this._inflate = null;
+      } else {
+        this._inflate[kTotalLength] = 0;
+        this._inflate[kBuffers] = [];
+
+        if (fin && this.params[`${endpoint}_no_context_takeover`]) {
+          this._inflate.reset();
+        }
+      }
+
+      callback(null, data);
+    });
+  }
+
+  /**
+   * Compress data.
+   *
+   * @param {(Buffer|String)} data Data to compress
+   * @param {Boolean} fin Specifies whether or not this is the last fragment
+   * @param {Function} callback Callback
+   * @private
+   */
+  _compress(data, fin, callback) {
+    const endpoint = this._isServer ? 'server' : 'client';
+
+    if (!this._deflate) {
+      const key = `${endpoint}_max_window_bits`;
+      const windowBits =
+        typeof this.params[key] !== 'number'
+          ? zlib.Z_DEFAULT_WINDOWBITS
+          : this.params[key];
+
+      this._deflate = zlib.createDeflateRaw({
+        ...this._options.zlibDeflateOptions,
+        windowBits
+      });
+
+      this._deflate[kTotalLength] = 0;
+      this._deflate[kBuffers] = [];
+
+      this._deflate.on('data', deflateOnData);
+    }
+
+    this._deflate[kCallback] = callback;
+
+    this._deflate.write(data);
+    this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
+      if (!this._deflate) {
+        //
+        // The deflate stream was closed while data was being processed.
+        //
+        return;
+      }
+
+      let data = bufferUtil.concat(
+        this._deflate[kBuffers],
+        this._deflate[kTotalLength]
+      );
+
+      if (fin) {
+        data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
+      }
+
+      //
+      // Ensure that the callback will not be called again in
+      // `PerMessageDeflate#cleanup()`.
+      //
+      this._deflate[kCallback] = null;
+
+      this._deflate[kTotalLength] = 0;
+      this._deflate[kBuffers] = [];
+
+      if (fin && this.params[`${endpoint}_no_context_takeover`]) {
+        this._deflate.reset();
+      }
+
+      callback(null, data);
+    });
+  }
+}
+
+module.exports = PerMessageDeflate;
+
+/**
+ * The listener of the `zlib.DeflateRaw` stream `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function deflateOnData(chunk) {
+  this[kBuffers].push(chunk);
+  this[kTotalLength] += chunk.length;
+}
+
+/**
+ * The listener of the `zlib.InflateRaw` stream `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function inflateOnData(chunk) {
+  this[kTotalLength] += chunk.length;
+
+  if (
+    this[kPerMessageDeflate]._maxPayload < 1 ||
+    this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
+  ) {
+    this[kBuffers].push(chunk);
+    return;
+  }
+
+  this[kError] = new RangeError('Max payload size exceeded');
+  this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
+  this[kError][kStatusCode] = 1009;
+  this.removeListener('data', inflateOnData);
+
+  //
+  // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the
+  // fact that in Node.js versions prior to 13.10.0, the callback for
+  // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing
+  // `zlib.reset()` ensures that either the callback is invoked or an error is
+  // emitted.
+  //
+  this.reset();
+}
+
+/**
+ * The listener of the `zlib.InflateRaw` stream `'error'` event.
+ *
+ * @param {Error} err The emitted error
+ * @private
+ */
+function inflateOnError(err) {
+  //
+  // There is no need to call `Zlib#close()` as the handle is automatically
+  // closed when an error is emitted.
+  //
+  this[kPerMessageDeflate]._inflate = null;
+
+  if (this[kError]) {
+    this[kCallback](this[kError]);
+    return;
+  }
+
+  err[kStatusCode] = 1007;
+  this[kCallback](err);
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/receiver.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/receiver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/receiver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,706 @@
+'use strict';
+
+const { Writable } = require('stream');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const {
+  BINARY_TYPES,
+  EMPTY_BUFFER,
+  kStatusCode,
+  kWebSocket
+} = require('./constants');
+const { concat, toArrayBuffer, unmask } = require('./buffer-util');
+const { isValidStatusCode, isValidUTF8 } = require('./validation');
+
+const FastBuffer = Buffer[Symbol.species];
+
+const GET_INFO = 0;
+const GET_PAYLOAD_LENGTH_16 = 1;
+const GET_PAYLOAD_LENGTH_64 = 2;
+const GET_MASK = 3;
+const GET_DATA = 4;
+const INFLATING = 5;
+const DEFER_EVENT = 6;
+
+/**
+ * HyBi Receiver implementation.
+ *
+ * @extends Writable
+ */
+class Receiver extends Writable {
+  /**
+   * Creates a Receiver instance.
+   *
+   * @param {Object} [options] Options object
+   * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
+   *     any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
+   *     multiple times in the same tick
+   * @param {String} [options.binaryType=nodebuffer] The type for binary data
+   * @param {Object} [options.extensions] An object containing the negotiated
+   *     extensions
+   * @param {Boolean} [options.isServer=false] Specifies whether to operate in
+   *     client or server mode
+   * @param {Number} [options.maxPayload=0] The maximum allowed message length
+   * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+   *     not to skip UTF-8 validation for text and close messages
+   */
+  constructor(options = {}) {
+    super();
+
+    this._allowSynchronousEvents =
+      options.allowSynchronousEvents !== undefined
+        ? options.allowSynchronousEvents
+        : true;
+    this._binaryType = options.binaryType || BINARY_TYPES[0];
+    this._extensions = options.extensions || {};
+    this._isServer = !!options.isServer;
+    this._maxPayload = options.maxPayload | 0;
+    this._skipUTF8Validation = !!options.skipUTF8Validation;
+    this[kWebSocket] = undefined;
+
+    this._bufferedBytes = 0;
+    this._buffers = [];
+
+    this._compressed = false;
+    this._payloadLength = 0;
+    this._mask = undefined;
+    this._fragmented = 0;
+    this._masked = false;
+    this._fin = false;
+    this._opcode = 0;
+
+    this._totalPayloadLength = 0;
+    this._messageLength = 0;
+    this._fragments = [];
+
+    this._errored = false;
+    this._loop = false;
+    this._state = GET_INFO;
+  }
+
+  /**
+   * Implements `Writable.prototype._write()`.
+   *
+   * @param {Buffer} chunk The chunk of data to write
+   * @param {String} encoding The character encoding of `chunk`
+   * @param {Function} cb Callback
+   * @private
+   */
+  _write(chunk, encoding, cb) {
+    if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
+
+    this._bufferedBytes += chunk.length;
+    this._buffers.push(chunk);
+    this.startLoop(cb);
+  }
+
+  /**
+   * Consumes `n` bytes from the buffered data.
+   *
+   * @param {Number} n The number of bytes to consume
+   * @return {Buffer} The consumed bytes
+   * @private
+   */
+  consume(n) {
+    this._bufferedBytes -= n;
+
+    if (n === this._buffers[0].length) return this._buffers.shift();
+
+    if (n < this._buffers[0].length) {
+      const buf = this._buffers[0];
+      this._buffers[0] = new FastBuffer(
+        buf.buffer,
+        buf.byteOffset + n,
+        buf.length - n
+      );
+
+      return new FastBuffer(buf.buffer, buf.byteOffset, n);
+    }
+
+    const dst = Buffer.allocUnsafe(n);
+
+    do {
+      const buf = this._buffers[0];
+      const offset = dst.length - n;
+
+      if (n >= buf.length) {
+        dst.set(this._buffers.shift(), offset);
+      } else {
+        dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
+        this._buffers[0] = new FastBuffer(
+          buf.buffer,
+          buf.byteOffset + n,
+          buf.length - n
+        );
+      }
+
+      n -= buf.length;
+    } while (n > 0);
+
+    return dst;
+  }
+
+  /**
+   * Starts the parsing loop.
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  startLoop(cb) {
+    this._loop = true;
+
+    do {
+      switch (this._state) {
+        case GET_INFO:
+          this.getInfo(cb);
+          break;
+        case GET_PAYLOAD_LENGTH_16:
+          this.getPayloadLength16(cb);
+          break;
+        case GET_PAYLOAD_LENGTH_64:
+          this.getPayloadLength64(cb);
+          break;
+        case GET_MASK:
+          this.getMask();
+          break;
+        case GET_DATA:
+          this.getData(cb);
+          break;
+        case INFLATING:
+        case DEFER_EVENT:
+          this._loop = false;
+          return;
+      }
+    } while (this._loop);
+
+    if (!this._errored) cb();
+  }
+
+  /**
+   * Reads the first two bytes of a frame.
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  getInfo(cb) {
+    if (this._bufferedBytes < 2) {
+      this._loop = false;
+      return;
+    }
+
+    const buf = this.consume(2);
+
+    if ((buf[0] & 0x30) !== 0x00) {
+      const error = this.createError(
+        RangeError,
+        'RSV2 and RSV3 must be clear',
+        true,
+        1002,
+        'WS_ERR_UNEXPECTED_RSV_2_3'
+      );
+
+      cb(error);
+      return;
+    }
+
+    const compressed = (buf[0] & 0x40) === 0x40;
+
+    if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
+      const error = this.createError(
+        RangeError,
+        'RSV1 must be clear',
+        true,
+        1002,
+        'WS_ERR_UNEXPECTED_RSV_1'
+      );
+
+      cb(error);
+      return;
+    }
+
+    this._fin = (buf[0] & 0x80) === 0x80;
+    this._opcode = buf[0] & 0x0f;
+    this._payloadLength = buf[1] & 0x7f;
+
+    if (this._opcode === 0x00) {
+      if (compressed) {
+        const error = this.createError(
+          RangeError,
+          'RSV1 must be clear',
+          true,
+          1002,
+          'WS_ERR_UNEXPECTED_RSV_1'
+        );
+
+        cb(error);
+        return;
+      }
+
+      if (!this._fragmented) {
+        const error = this.createError(
+          RangeError,
+          'invalid opcode 0',
+          true,
+          1002,
+          'WS_ERR_INVALID_OPCODE'
+        );
+
+        cb(error);
+        return;
+      }
+
+      this._opcode = this._fragmented;
+    } else if (this._opcode === 0x01 || this._opcode === 0x02) {
+      if (this._fragmented) {
+        const error = this.createError(
+          RangeError,
+          `invalid opcode ${this._opcode}`,
+          true,
+          1002,
+          'WS_ERR_INVALID_OPCODE'
+        );
+
+        cb(error);
+        return;
+      }
+
+      this._compressed = compressed;
+    } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
+      if (!this._fin) {
+        const error = this.createError(
+          RangeError,
+          'FIN must be set',
+          true,
+          1002,
+          'WS_ERR_EXPECTED_FIN'
+        );
+
+        cb(error);
+        return;
+      }
+
+      if (compressed) {
+        const error = this.createError(
+          RangeError,
+          'RSV1 must be clear',
+          true,
+          1002,
+          'WS_ERR_UNEXPECTED_RSV_1'
+        );
+
+        cb(error);
+        return;
+      }
+
+      if (
+        this._payloadLength > 0x7d ||
+        (this._opcode === 0x08 && this._payloadLength === 1)
+      ) {
+        const error = this.createError(
+          RangeError,
+          `invalid payload length ${this._payloadLength}`,
+          true,
+          1002,
+          'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
+        );
+
+        cb(error);
+        return;
+      }
+    } else {
+      const error = this.createError(
+        RangeError,
+        `invalid opcode ${this._opcode}`,
+        true,
+        1002,
+        'WS_ERR_INVALID_OPCODE'
+      );
+
+      cb(error);
+      return;
+    }
+
+    if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
+    this._masked = (buf[1] & 0x80) === 0x80;
+
+    if (this._isServer) {
+      if (!this._masked) {
+        const error = this.createError(
+          RangeError,
+          'MASK must be set',
+          true,
+          1002,
+          'WS_ERR_EXPECTED_MASK'
+        );
+
+        cb(error);
+        return;
+      }
+    } else if (this._masked) {
+      const error = this.createError(
+        RangeError,
+        'MASK must be clear',
+        true,
+        1002,
+        'WS_ERR_UNEXPECTED_MASK'
+      );
+
+      cb(error);
+      return;
+    }
+
+    if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
+    else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
+    else this.haveLength(cb);
+  }
+
+  /**
+   * Gets extended payload length (7+16).
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  getPayloadLength16(cb) {
+    if (this._bufferedBytes < 2) {
+      this._loop = false;
+      return;
+    }
+
+    this._payloadLength = this.consume(2).readUInt16BE(0);
+    this.haveLength(cb);
+  }
+
+  /**
+   * Gets extended payload length (7+64).
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  getPayloadLength64(cb) {
+    if (this._bufferedBytes < 8) {
+      this._loop = false;
+      return;
+    }
+
+    const buf = this.consume(8);
+    const num = buf.readUInt32BE(0);
+
+    //
+    // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
+    // if payload length is greater than this number.
+    //
+    if (num > Math.pow(2, 53 - 32) - 1) {
+      const error = this.createError(
+        RangeError,
+        'Unsupported WebSocket frame: payload length > 2^53 - 1',
+        false,
+        1009,
+        'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
+      );
+
+      cb(error);
+      return;
+    }
+
+    this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
+    this.haveLength(cb);
+  }
+
+  /**
+   * Payload length has been read.
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  haveLength(cb) {
+    if (this._payloadLength && this._opcode < 0x08) {
+      this._totalPayloadLength += this._payloadLength;
+      if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
+        const error = this.createError(
+          RangeError,
+          'Max payload size exceeded',
+          false,
+          1009,
+          'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
+        );
+
+        cb(error);
+        return;
+      }
+    }
+
+    if (this._masked) this._state = GET_MASK;
+    else this._state = GET_DATA;
+  }
+
+  /**
+   * Reads mask bytes.
+   *
+   * @private
+   */
+  getMask() {
+    if (this._bufferedBytes < 4) {
+      this._loop = false;
+      return;
+    }
+
+    this._mask = this.consume(4);
+    this._state = GET_DATA;
+  }
+
+  /**
+   * Reads data bytes.
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  getData(cb) {
+    let data = EMPTY_BUFFER;
+
+    if (this._payloadLength) {
+      if (this._bufferedBytes < this._payloadLength) {
+        this._loop = false;
+        return;
+      }
+
+      data = this.consume(this._payloadLength);
+
+      if (
+        this._masked &&
+        (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0
+      ) {
+        unmask(data, this._mask);
+      }
+    }
+
+    if (this._opcode > 0x07) {
+      this.controlMessage(data, cb);
+      return;
+    }
+
+    if (this._compressed) {
+      this._state = INFLATING;
+      this.decompress(data, cb);
+      return;
+    }
+
+    if (data.length) {
+      //
+      // This message is not compressed so its length is the sum of the payload
+      // length of all fragments.
+      //
+      this._messageLength = this._totalPayloadLength;
+      this._fragments.push(data);
+    }
+
+    this.dataMessage(cb);
+  }
+
+  /**
+   * Decompresses data.
+   *
+   * @param {Buffer} data Compressed data
+   * @param {Function} cb Callback
+   * @private
+   */
+  decompress(data, cb) {
+    const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+    perMessageDeflate.decompress(data, this._fin, (err, buf) => {
+      if (err) return cb(err);
+
+      if (buf.length) {
+        this._messageLength += buf.length;
+        if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
+          const error = this.createError(
+            RangeError,
+            'Max payload size exceeded',
+            false,
+            1009,
+            'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
+          );
+
+          cb(error);
+          return;
+        }
+
+        this._fragments.push(buf);
+      }
+
+      this.dataMessage(cb);
+      if (this._state === GET_INFO) this.startLoop(cb);
+    });
+  }
+
+  /**
+   * Handles a data message.
+   *
+   * @param {Function} cb Callback
+   * @private
+   */
+  dataMessage(cb) {
+    if (!this._fin) {
+      this._state = GET_INFO;
+      return;
+    }
+
+    const messageLength = this._messageLength;
+    const fragments = this._fragments;
+
+    this._totalPayloadLength = 0;
+    this._messageLength = 0;
+    this._fragmented = 0;
+    this._fragments = [];
+
+    if (this._opcode === 2) {
+      let data;
+
+      if (this._binaryType === 'nodebuffer') {
+        data = concat(fragments, messageLength);
+      } else if (this._binaryType === 'arraybuffer') {
+        data = toArrayBuffer(concat(fragments, messageLength));
+      } else if (this._binaryType === 'blob') {
+        data = new Blob(fragments);
+      } else {
+        data = fragments;
+      }
+
+      if (this._allowSynchronousEvents) {
+        this.emit('message', data, true);
+        this._state = GET_INFO;
+      } else {
+        this._state = DEFER_EVENT;
+        setImmediate(() => {
+          this.emit('message', data, true);
+          this._state = GET_INFO;
+          this.startLoop(cb);
+        });
+      }
+    } else {
+      const buf = concat(fragments, messageLength);
+
+      if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
+        const error = this.createError(
+          Error,
+          'invalid UTF-8 sequence',
+          true,
+          1007,
+          'WS_ERR_INVALID_UTF8'
+        );
+
+        cb(error);
+        return;
+      }
+
+      if (this._state === INFLATING || this._allowSynchronousEvents) {
+        this.emit('message', buf, false);
+        this._state = GET_INFO;
+      } else {
+        this._state = DEFER_EVENT;
+        setImmediate(() => {
+          this.emit('message', buf, false);
+          this._state = GET_INFO;
+          this.startLoop(cb);
+        });
+      }
+    }
+  }
+
+  /**
+   * Handles a control message.
+   *
+   * @param {Buffer} data Data to handle
+   * @return {(Error|RangeError|undefined)} A possible error
+   * @private
+   */
+  controlMessage(data, cb) {
+    if (this._opcode === 0x08) {
+      if (data.length === 0) {
+        this._loop = false;
+        this.emit('conclude', 1005, EMPTY_BUFFER);
+        this.end();
+      } else {
+        const code = data.readUInt16BE(0);
+
+        if (!isValidStatusCode(code)) {
+          const error = this.createError(
+            RangeError,
+            `invalid status code ${code}`,
+            true,
+            1002,
+            'WS_ERR_INVALID_CLOSE_CODE'
+          );
+
+          cb(error);
+          return;
+        }
+
+        const buf = new FastBuffer(
+          data.buffer,
+          data.byteOffset + 2,
+          data.length - 2
+        );
+
+        if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
+          const error = this.createError(
+            Error,
+            'invalid UTF-8 sequence',
+            true,
+            1007,
+            'WS_ERR_INVALID_UTF8'
+          );
+
+          cb(error);
+          return;
+        }
+
+        this._loop = false;
+        this.emit('conclude', code, buf);
+        this.end();
+      }
+
+      this._state = GET_INFO;
+      return;
+    }
+
+    if (this._allowSynchronousEvents) {
+      this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);
+      this._state = GET_INFO;
+    } else {
+      this._state = DEFER_EVENT;
+      setImmediate(() => {
+        this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);
+        this._state = GET_INFO;
+        this.startLoop(cb);
+      });
+    }
+  }
+
+  /**
+   * Builds an error object.
+   *
+   * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
+   * @param {String} message The error message
+   * @param {Boolean} prefix Specifies whether or not to add a default prefix to
+   *     `message`
+   * @param {Number} statusCode The status code
+   * @param {String} errorCode The exposed error code
+   * @return {(Error|RangeError)} The error
+   * @private
+   */
+  createError(ErrorCtor, message, prefix, statusCode, errorCode) {
+    this._loop = false;
+    this._errored = true;
+
+    const err = new ErrorCtor(
+      prefix ? `Invalid WebSocket frame: ${message}` : message
+    );
+
+    Error.captureStackTrace(err, this.createError);
+    err.code = errorCode;
+    err[kStatusCode] = statusCode;
+    return err;
+  }
+}
+
+module.exports = Receiver;
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/sender.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/sender.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/sender.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,607 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */
+
+'use strict';
+
+const { Duplex } = require('stream');
+const { randomFillSync } = require('crypto');
+const {
+  types: { isUint8Array }
+} = require('util');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');
+const { isBlob, isValidStatusCode } = require('./validation');
+const { mask: applyMask, toBuffer } = require('./buffer-util');
+
+const kByteLength = Symbol('kByteLength');
+const maskBuffer = Buffer.alloc(4);
+const RANDOM_POOL_SIZE = 8 * 1024;
+let randomPool;
+let randomPoolPointer = RANDOM_POOL_SIZE;
+
+const DEFAULT = 0;
+const DEFLATING = 1;
+const GET_BLOB_DATA = 2;
+
+/**
+ * HyBi Sender implementation.
+ */
+class Sender {
+  /**
+   * Creates a Sender instance.
+   *
+   * @param {Duplex} socket The connection socket
+   * @param {Object} [extensions] An object containing the negotiated extensions
+   * @param {Function} [generateMask] The function used to generate the masking
+   *     key
+   */
+  constructor(socket, extensions, generateMask) {
+    this._extensions = extensions || {};
+
+    if (generateMask) {
+      this._generateMask = generateMask;
+      this._maskBuffer = Buffer.alloc(4);
+    }
+
+    this._socket = socket;
+
+    this._firstFragment = true;
+    this._compress = false;
+
+    this._bufferedBytes = 0;
+    this._queue = [];
+    this._state = DEFAULT;
+    this.onerror = NOOP;
+    this[kWebSocket] = undefined;
+  }
+
+  /**
+   * Frames a piece of data according to the HyBi WebSocket protocol.
+   *
+   * @param {(Buffer|String)} data The data to frame
+   * @param {Object} options Options object
+   * @param {Boolean} [options.fin=false] Specifies whether or not to set the
+   *     FIN bit
+   * @param {Function} [options.generateMask] The function used to generate the
+   *     masking key
+   * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+   *     `data`
+   * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
+   *     key
+   * @param {Number} options.opcode The opcode
+   * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
+   *     modified
+   * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
+   *     RSV1 bit
+   * @return {(Buffer|String)[]} The framed data
+   * @public
+   */
+  static frame(data, options) {
+    let mask;
+    let merge = false;
+    let offset = 2;
+    let skipMasking = false;
+
+    if (options.mask) {
+      mask = options.maskBuffer || maskBuffer;
+
+      if (options.generateMask) {
+        options.generateMask(mask);
+      } else {
+        if (randomPoolPointer === RANDOM_POOL_SIZE) {
+          /* istanbul ignore else  */
+          if (randomPool === undefined) {
+            //
+            // This is lazily initialized because server-sent frames must not
+            // be masked so it may never be used.
+            //
+            randomPool = Buffer.alloc(RANDOM_POOL_SIZE);
+          }
+
+          randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
+          randomPoolPointer = 0;
+        }
+
+        mask[0] = randomPool[randomPoolPointer++];
+        mask[1] = randomPool[randomPoolPointer++];
+        mask[2] = randomPool[randomPoolPointer++];
+        mask[3] = randomPool[randomPoolPointer++];
+      }
+
+      skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
+      offset = 6;
+    }
+
+    let dataLength;
+
+    if (typeof data === 'string') {
+      if (
+        (!options.mask || skipMasking) &&
+        options[kByteLength] !== undefined
+      ) {
+        dataLength = options[kByteLength];
+      } else {
+        data = Buffer.from(data);
+        dataLength = data.length;
+      }
+    } else {
+      dataLength = data.length;
+      merge = options.mask && options.readOnly && !skipMasking;
+    }
+
+    let payloadLength = dataLength;
+
+    if (dataLength >= 65536) {
+      offset += 8;
+      payloadLength = 127;
+    } else if (dataLength > 125) {
+      offset += 2;
+      payloadLength = 126;
+    }
+
+    const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);
+
+    target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
+    if (options.rsv1) target[0] |= 0x40;
+
+    target[1] = payloadLength;
+
+    if (payloadLength === 126) {
+      target.writeUInt16BE(dataLength, 2);
+    } else if (payloadLength === 127) {
+      target[2] = target[3] = 0;
+      target.writeUIntBE(dataLength, 4, 6);
+    }
+
+    if (!options.mask) return [target, data];
+
+    target[1] |= 0x80;
+    target[offset - 4] = mask[0];
+    target[offset - 3] = mask[1];
+    target[offset - 2] = mask[2];
+    target[offset - 1] = mask[3];
+
+    if (skipMasking) return [target, data];
+
+    if (merge) {
+      applyMask(data, mask, target, offset, dataLength);
+      return [target];
+    }
+
+    applyMask(data, mask, data, 0, dataLength);
+    return [target, data];
+  }
+
+  /**
+   * Sends a close message to the other peer.
+   *
+   * @param {Number} [code] The status code component of the body
+   * @param {(String|Buffer)} [data] The message component of the body
+   * @param {Boolean} [mask=false] Specifies whether or not to mask the message
+   * @param {Function} [cb] Callback
+   * @public
+   */
+  close(code, data, mask, cb) {
+    let buf;
+
+    if (code === undefined) {
+      buf = EMPTY_BUFFER;
+    } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
+      throw new TypeError('First argument must be a valid error code number');
+    } else if (data === undefined || !data.length) {
+      buf = Buffer.allocUnsafe(2);
+      buf.writeUInt16BE(code, 0);
+    } else {
+      const length = Buffer.byteLength(data);
+
+      if (length > 123) {
+        throw new RangeError('The message must not be greater than 123 bytes');
+      }
+
+      buf = Buffer.allocUnsafe(2 + length);
+      buf.writeUInt16BE(code, 0);
+
+      if (typeof data === 'string') {
+        buf.write(data, 2);
+      } else if (isUint8Array(data)) {
+        buf.set(data, 2);
+      } else {
+        throw new TypeError('Second argument must be a string or a Uint8Array');
+      }
+    }
+
+    const options = {
+      [kByteLength]: buf.length,
+      fin: true,
+      generateMask: this._generateMask,
+      mask,
+      maskBuffer: this._maskBuffer,
+      opcode: 0x08,
+      readOnly: false,
+      rsv1: false
+    };
+
+    if (this._state !== DEFAULT) {
+      this.enqueue([this.dispatch, buf, false, options, cb]);
+    } else {
+      this.sendFrame(Sender.frame(buf, options), cb);
+    }
+  }
+
+  /**
+   * Sends a ping message to the other peer.
+   *
+   * @param {*} data The message to send
+   * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
+   * @param {Function} [cb] Callback
+   * @public
+   */
+  ping(data, mask, cb) {
+    let byteLength;
+    let readOnly;
+
+    if (typeof data === 'string') {
+      byteLength = Buffer.byteLength(data);
+      readOnly = false;
+    } else if (isBlob(data)) {
+      byteLength = data.size;
+      readOnly = false;
+    } else {
+      data = toBuffer(data);
+      byteLength = data.length;
+      readOnly = toBuffer.readOnly;
+    }
+
+    if (byteLength > 125) {
+      throw new RangeError('The data size must not be greater than 125 bytes');
+    }
+
+    const options = {
+      [kByteLength]: byteLength,
+      fin: true,
+      generateMask: this._generateMask,
+      mask,
+      maskBuffer: this._maskBuffer,
+      opcode: 0x09,
+      readOnly,
+      rsv1: false
+    };
+
+    if (isBlob(data)) {
+      if (this._state !== DEFAULT) {
+        this.enqueue([this.getBlobData, data, false, options, cb]);
+      } else {
+        this.getBlobData(data, false, options, cb);
+      }
+    } else if (this._state !== DEFAULT) {
+      this.enqueue([this.dispatch, data, false, options, cb]);
+    } else {
+      this.sendFrame(Sender.frame(data, options), cb);
+    }
+  }
+
+  /**
+   * Sends a pong message to the other peer.
+   *
+   * @param {*} data The message to send
+   * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
+   * @param {Function} [cb] Callback
+   * @public
+   */
+  pong(data, mask, cb) {
+    let byteLength;
+    let readOnly;
+
+    if (typeof data === 'string') {
+      byteLength = Buffer.byteLength(data);
+      readOnly = false;
+    } else if (isBlob(data)) {
+      byteLength = data.size;
+      readOnly = false;
+    } else {
+      data = toBuffer(data);
+      byteLength = data.length;
+      readOnly = toBuffer.readOnly;
+    }
+
+    if (byteLength > 125) {
+      throw new RangeError('The data size must not be greater than 125 bytes');
+    }
+
+    const options = {
+      [kByteLength]: byteLength,
+      fin: true,
+      generateMask: this._generateMask,
+      mask,
+      maskBuffer: this._maskBuffer,
+      opcode: 0x0a,
+      readOnly,
+      rsv1: false
+    };
+
+    if (isBlob(data)) {
+      if (this._state !== DEFAULT) {
+        this.enqueue([this.getBlobData, data, false, options, cb]);
+      } else {
+        this.getBlobData(data, false, options, cb);
+      }
+    } else if (this._state !== DEFAULT) {
+      this.enqueue([this.dispatch, data, false, options, cb]);
+    } else {
+      this.sendFrame(Sender.frame(data, options), cb);
+    }
+  }
+
+  /**
+   * Sends a data message to the other peer.
+   *
+   * @param {*} data The message to send
+   * @param {Object} options Options object
+   * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
+   *     or text
+   * @param {Boolean} [options.compress=false] Specifies whether or not to
+   *     compress `data`
+   * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
+   *     last one
+   * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+   *     `data`
+   * @param {Function} [cb] Callback
+   * @public
+   */
+  send(data, options, cb) {
+    const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+    let opcode = options.binary ? 2 : 1;
+    let rsv1 = options.compress;
+
+    let byteLength;
+    let readOnly;
+
+    if (typeof data === 'string') {
+      byteLength = Buffer.byteLength(data);
+      readOnly = false;
+    } else if (isBlob(data)) {
+      byteLength = data.size;
+      readOnly = false;
+    } else {
+      data = toBuffer(data);
+      byteLength = data.length;
+      readOnly = toBuffer.readOnly;
+    }
+
+    if (this._firstFragment) {
+      this._firstFragment = false;
+      if (
+        rsv1 &&
+        perMessageDeflate &&
+        perMessageDeflate.params[
+          perMessageDeflate._isServer
+            ? 'server_no_context_takeover'
+            : 'client_no_context_takeover'
+        ]
+      ) {
+        rsv1 = byteLength >= perMessageDeflate._threshold;
+      }
+      this._compress = rsv1;
+    } else {
+      rsv1 = false;
+      opcode = 0;
+    }
+
+    if (options.fin) this._firstFragment = true;
+
+    const opts = {
+      [kByteLength]: byteLength,
+      fin: options.fin,
+      generateMask: this._generateMask,
+      mask: options.mask,
+      maskBuffer: this._maskBuffer,
+      opcode,
+      readOnly,
+      rsv1
+    };
+
+    if (isBlob(data)) {
+      if (this._state !== DEFAULT) {
+        this.enqueue([this.getBlobData, data, this._compress, opts, cb]);
+      } else {
+        this.getBlobData(data, this._compress, opts, cb);
+      }
+    } else if (this._state !== DEFAULT) {
+      this.enqueue([this.dispatch, data, this._compress, opts, cb]);
+    } else {
+      this.dispatch(data, this._compress, opts, cb);
+    }
+  }
+
+  /**
+   * Gets the contents of a blob as binary data.
+   *
+   * @param {Blob} blob The blob
+   * @param {Boolean} [compress=false] Specifies whether or not to compress
+   *     the data
+   * @param {Object} options Options object
+   * @param {Boolean} [options.fin=false] Specifies whether or not to set the
+   *     FIN bit
+   * @param {Function} [options.generateMask] The function used to generate the
+   *     masking key
+   * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+   *     `data`
+   * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
+   *     key
+   * @param {Number} options.opcode The opcode
+   * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
+   *     modified
+   * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
+   *     RSV1 bit
+   * @param {Function} [cb] Callback
+   * @private
+   */
+  getBlobData(blob, compress, options, cb) {
+    this._bufferedBytes += options[kByteLength];
+    this._state = GET_BLOB_DATA;
+
+    blob
+      .arrayBuffer()
+      .then((arrayBuffer) => {
+        if (this._socket.destroyed) {
+          const err = new Error(
+            'The socket was closed while the blob was being read'
+          );
+
+          //
+          // `callCallbacks` is called in the next tick to ensure that errors
+          // that might be thrown in the callbacks behave like errors thrown
+          // outside the promise chain.
+          //
+          process.nextTick(callCallbacks, this, err, cb);
+          return;
+        }
+
+        this._bufferedBytes -= options[kByteLength];
+        const data = toBuffer(arrayBuffer);
+
+        if (!compress) {
+          this._state = DEFAULT;
+          this.sendFrame(Sender.frame(data, options), cb);
+          this.dequeue();
+        } else {
+          this.dispatch(data, compress, options, cb);
+        }
+      })
+      .catch((err) => {
+        //
+        // `onError` is called in the next tick for the same reason that
+        // `callCallbacks` above is.
+        //
+        process.nextTick(onError, this, err, cb);
+      });
+  }
+
+  /**
+   * Dispatches a message.
+   *
+   * @param {(Buffer|String)} data The message to send
+   * @param {Boolean} [compress=false] Specifies whether or not to compress
+   *     `data`
+   * @param {Object} options Options object
+   * @param {Boolean} [options.fin=false] Specifies whether or not to set the
+   *     FIN bit
+   * @param {Function} [options.generateMask] The function used to generate the
+   *     masking key
+   * @param {Boolean} [options.mask=false] Specifies whether or not to mask
+   *     `data`
+   * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
+   *     key
+   * @param {Number} options.opcode The opcode
+   * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
+   *     modified
+   * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
+   *     RSV1 bit
+   * @param {Function} [cb] Callback
+   * @private
+   */
+  dispatch(data, compress, options, cb) {
+    if (!compress) {
+      this.sendFrame(Sender.frame(data, options), cb);
+      return;
+    }
+
+    const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+    this._bufferedBytes += options[kByteLength];
+    this._state = DEFLATING;
+    perMessageDeflate.compress(data, options.fin, (_, buf) => {
+      if (this._socket.destroyed) {
+        const err = new Error(
+          'The socket was closed while data was being compressed'
+        );
+
+        callCallbacks(this, err, cb);
+        return;
+      }
+
+      this._bufferedBytes -= options[kByteLength];
+      this._state = DEFAULT;
+      options.readOnly = false;
+      this.sendFrame(Sender.frame(buf, options), cb);
+      this.dequeue();
+    });
+  }
+
+  /**
+   * Executes queued send operations.
+   *
+   * @private
+   */
+  dequeue() {
+    while (this._state === DEFAULT && this._queue.length) {
+      const params = this._queue.shift();
+
+      this._bufferedBytes -= params[3][kByteLength];
+      Reflect.apply(params[0], this, params.slice(1));
+    }
+  }
+
+  /**
+   * Enqueues a send operation.
+   *
+   * @param {Array} params Send operation parameters.
+   * @private
+   */
+  enqueue(params) {
+    this._bufferedBytes += params[3][kByteLength];
+    this._queue.push(params);
+  }
+
+  /**
+   * Sends a frame.
+   *
+   * @param {(Buffer | String)[]} list The frame to send
+   * @param {Function} [cb] Callback
+   * @private
+   */
+  sendFrame(list, cb) {
+    if (list.length === 2) {
+      this._socket.cork();
+      this._socket.write(list[0]);
+      this._socket.write(list[1], cb);
+      this._socket.uncork();
+    } else {
+      this._socket.write(list[0], cb);
+    }
+  }
+}
+
+module.exports = Sender;
+
+/**
+ * Calls queued callbacks with an error.
+ *
+ * @param {Sender} sender The `Sender` instance
+ * @param {Error} err The error to call the callbacks with
+ * @param {Function} [cb] The first callback
+ * @private
+ */
+function callCallbacks(sender, err, cb) {
+  if (typeof cb === 'function') cb(err);
+
+  for (let i = 0; i < sender._queue.length; i++) {
+    const params = sender._queue[i];
+    const callback = params[params.length - 1];
+
+    if (typeof callback === 'function') callback(err);
+  }
+}
+
+/**
+ * Handles a `Sender` error.
+ *
+ * @param {Sender} sender The `Sender` instance
+ * @param {Error} err The error
+ * @param {Function} [cb] The first pending callback
+ * @private
+ */
+function onError(sender, err, cb) {
+  callCallbacks(sender, err, cb);
+  sender.onerror(err);
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/stream.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/stream.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/stream.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,161 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^WebSocket$" }] */
+'use strict';
+
+const WebSocket = require('./websocket');
+const { Duplex } = require('stream');
+
+/**
+ * Emits the `'close'` event on a stream.
+ *
+ * @param {Duplex} stream The stream.
+ * @private
+ */
+function emitClose(stream) {
+  stream.emit('close');
+}
+
+/**
+ * The listener of the `'end'` event.
+ *
+ * @private
+ */
+function duplexOnEnd() {
+  if (!this.destroyed && this._writableState.finished) {
+    this.destroy();
+  }
+}
+
+/**
+ * The listener of the `'error'` event.
+ *
+ * @param {Error} err The error
+ * @private
+ */
+function duplexOnError(err) {
+  this.removeListener('error', duplexOnError);
+  this.destroy();
+  if (this.listenerCount('error') === 0) {
+    // Do not suppress the throwing behavior.
+    this.emit('error', err);
+  }
+}
+
+/**
+ * Wraps a `WebSocket` in a duplex stream.
+ *
+ * @param {WebSocket} ws The `WebSocket` to wrap
+ * @param {Object} [options] The options for the `Duplex` constructor
+ * @return {Duplex} The duplex stream
+ * @public
+ */
+function createWebSocketStream(ws, options) {
+  let terminateOnDestroy = true;
+
+  const duplex = new Duplex({
+    ...options,
+    autoDestroy: false,
+    emitClose: false,
+    objectMode: false,
+    writableObjectMode: false
+  });
+
+  ws.on('message', function message(msg, isBinary) {
+    const data =
+      !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
+
+    if (!duplex.push(data)) ws.pause();
+  });
+
+  ws.once('error', function error(err) {
+    if (duplex.destroyed) return;
+
+    // Prevent `ws.terminate()` from being called by `duplex._destroy()`.
+    //
+    // - If the `'error'` event is emitted before the `'open'` event, then
+    //   `ws.terminate()` is a noop as no socket is assigned.
+    // - Otherwise, the error is re-emitted by the listener of the `'error'`
+    //   event of the `Receiver` object. The listener already closes the
+    //   connection by calling `ws.close()`. This allows a close frame to be
+    //   sent to the other peer. If `ws.terminate()` is called right after this,
+    //   then the close frame might not be sent.
+    terminateOnDestroy = false;
+    duplex.destroy(err);
+  });
+
+  ws.once('close', function close() {
+    if (duplex.destroyed) return;
+
+    duplex.push(null);
+  });
+
+  duplex._destroy = function (err, callback) {
+    if (ws.readyState === ws.CLOSED) {
+      callback(err);
+      process.nextTick(emitClose, duplex);
+      return;
+    }
+
+    let called = false;
+
+    ws.once('error', function error(err) {
+      called = true;
+      callback(err);
+    });
+
+    ws.once('close', function close() {
+      if (!called) callback(err);
+      process.nextTick(emitClose, duplex);
+    });
+
+    if (terminateOnDestroy) ws.terminate();
+  };
+
+  duplex._final = function (callback) {
+    if (ws.readyState === ws.CONNECTING) {
+      ws.once('open', function open() {
+        duplex._final(callback);
+      });
+      return;
+    }
+
+    // If the value of the `_socket` property is `null` it means that `ws` is a
+    // client websocket and the handshake failed. In fact, when this happens, a
+    // socket is never assigned to the websocket. Wait for the `'error'` event
+    // that will be emitted by the websocket.
+    if (ws._socket === null) return;
+
+    if (ws._socket._writableState.finished) {
+      callback();
+      if (duplex._readableState.endEmitted) duplex.destroy();
+    } else {
+      ws._socket.once('finish', function finish() {
+        // `duplex` is not destroyed here because the `'end'` event will be
+        // emitted on `duplex` after this `'finish'` event. The EOF signaling
+        // `null` chunk is, in fact, pushed when the websocket emits `'close'`.
+        callback();
+      });
+      ws.close();
+    }
+  };
+
+  duplex._read = function () {
+    if (ws.isPaused) ws.resume();
+  };
+
+  duplex._write = function (chunk, encoding, callback) {
+    if (ws.readyState === ws.CONNECTING) {
+      ws.once('open', function open() {
+        duplex._write(chunk, encoding, callback);
+      });
+      return;
+    }
+
+    ws.send(chunk, callback);
+  };
+
+  duplex.on('end', duplexOnEnd);
+  duplex.on('error', duplexOnError);
+  return duplex;
+}
+
+module.exports = createWebSocketStream;
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/subprotocol.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/subprotocol.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/subprotocol.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,62 @@
+'use strict';
+
+const { tokenChars } = require('./validation');
+
+/**
+ * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
+ *
+ * @param {String} header The field value of the header
+ * @return {Set} The subprotocol names
+ * @public
+ */
+function parse(header) {
+  const protocols = new Set();
+  let start = -1;
+  let end = -1;
+  let i = 0;
+
+  for (i; i < header.length; i++) {
+    const code = header.charCodeAt(i);
+
+    if (end === -1 && tokenChars[code] === 1) {
+      if (start === -1) start = i;
+    } else if (
+      i !== 0 &&
+      (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
+    ) {
+      if (end === -1 && start !== -1) end = i;
+    } else if (code === 0x2c /* ',' */) {
+      if (start === -1) {
+        throw new SyntaxError(`Unexpected character at index ${i}`);
+      }
+
+      if (end === -1) end = i;
+
+      const protocol = header.slice(start, end);
+
+      if (protocols.has(protocol)) {
+        throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
+      }
+
+      protocols.add(protocol);
+      start = end = -1;
+    } else {
+      throw new SyntaxError(`Unexpected character at index ${i}`);
+    }
+  }
+
+  if (start === -1 || end !== -1) {
+    throw new SyntaxError('Unexpected end of input');
+  }
+
+  const protocol = header.slice(start, i);
+
+  if (protocols.has(protocol)) {
+    throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
+  }
+
+  protocols.add(protocol);
+  return protocols;
+}
+
+module.exports = { parse };
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/validation.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/validation.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/validation.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,152 @@
+'use strict';
+
+const { isUtf8 } = require('buffer');
+
+const { hasBlob } = require('./constants');
+
+//
+// Allowed token characters:
+//
+// '!', '#', '$', '%', '&', ''', '*', '+', '-',
+// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
+//
+// tokenChars[32] === 0 // ' '
+// tokenChars[33] === 1 // '!'
+// tokenChars[34] === 0 // '"'
+// ...
+//
+// prettier-ignore
+const tokenChars = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
+  0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
+];
+
+/**
+ * Checks if a status code is allowed in a close frame.
+ *
+ * @param {Number} code The status code
+ * @return {Boolean} `true` if the status code is valid, else `false`
+ * @public
+ */
+function isValidStatusCode(code) {
+  return (
+    (code >= 1000 &&
+      code <= 1014 &&
+      code !== 1004 &&
+      code !== 1005 &&
+      code !== 1006) ||
+    (code >= 3000 && code <= 4999)
+  );
+}
+
+/**
+ * Checks if a given buffer contains only correct UTF-8.
+ * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
+ * Markus Kuhn.
+ *
+ * @param {Buffer} buf The buffer to check
+ * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
+ * @public
+ */
+function _isValidUTF8(buf) {
+  const len = buf.length;
+  let i = 0;
+
+  while (i < len) {
+    if ((buf[i] & 0x80) === 0) {
+      // 0xxxxxxx
+      i++;
+    } else if ((buf[i] & 0xe0) === 0xc0) {
+      // 110xxxxx 10xxxxxx
+      if (
+        i + 1 === len ||
+        (buf[i + 1] & 0xc0) !== 0x80 ||
+        (buf[i] & 0xfe) === 0xc0 // Overlong
+      ) {
+        return false;
+      }
+
+      i += 2;
+    } else if ((buf[i] & 0xf0) === 0xe0) {
+      // 1110xxxx 10xxxxxx 10xxxxxx
+      if (
+        i + 2 >= len ||
+        (buf[i + 1] & 0xc0) !== 0x80 ||
+        (buf[i + 2] & 0xc0) !== 0x80 ||
+        (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong
+        (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)
+      ) {
+        return false;
+      }
+
+      i += 3;
+    } else if ((buf[i] & 0xf8) === 0xf0) {
+      // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+      if (
+        i + 3 >= len ||
+        (buf[i + 1] & 0xc0) !== 0x80 ||
+        (buf[i + 2] & 0xc0) !== 0x80 ||
+        (buf[i + 3] & 0xc0) !== 0x80 ||
+        (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong
+        (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||
+        buf[i] > 0xf4 // > U+10FFFF
+      ) {
+        return false;
+      }
+
+      i += 4;
+    } else {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * Determines whether a value is a `Blob`.
+ *
+ * @param {*} value The value to be tested
+ * @return {Boolean} `true` if `value` is a `Blob`, else `false`
+ * @private
+ */
+function isBlob(value) {
+  return (
+    hasBlob &&
+    typeof value === 'object' &&
+    typeof value.arrayBuffer === 'function' &&
+    typeof value.type === 'string' &&
+    typeof value.stream === 'function' &&
+    (value[Symbol.toStringTag] === 'Blob' ||
+      value[Symbol.toStringTag] === 'File')
+  );
+}
+
+module.exports = {
+  isBlob,
+  isValidStatusCode,
+  isValidUTF8: _isValidUTF8,
+  tokenChars
+};
+
+if (isUtf8) {
+  module.exports.isValidUTF8 = function (buf) {
+    return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);
+  };
+} /* istanbul ignore else  */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {
+  try {
+    const isValidUTF8 = require('utf-8-validate');
+
+    module.exports.isValidUTF8 = function (buf) {
+      return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
+    };
+  } catch (e) {
+    // Continue regardless of the error.
+  }
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/websocket-server.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/websocket-server.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/websocket-server.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,554 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
+
+'use strict';
+
+const EventEmitter = require('events');
+const http = require('http');
+const { Duplex } = require('stream');
+const { createHash } = require('crypto');
+
+const extension = require('./extension');
+const PerMessageDeflate = require('./permessage-deflate');
+const subprotocol = require('./subprotocol');
+const WebSocket = require('./websocket');
+const { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');
+
+const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
+
+const RUNNING = 0;
+const CLOSING = 1;
+const CLOSED = 2;
+
+/**
+ * Class representing a WebSocket server.
+ *
+ * @extends EventEmitter
+ */
+class WebSocketServer extends EventEmitter {
+  /**
+   * Create a `WebSocketServer` instance.
+   *
+   * @param {Object} options Configuration options
+   * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
+   *     any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
+   *     multiple times in the same tick
+   * @param {Boolean} [options.autoPong=true] Specifies whether or not to
+   *     automatically send a pong in response to a ping
+   * @param {Number} [options.backlog=511] The maximum length of the queue of
+   *     pending connections
+   * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
+   *     track clients
+   * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to
+   *     wait for the closing handshake to finish after `websocket.close()` is
+   *     called
+   * @param {Function} [options.handleProtocols] A hook to handle protocols
+   * @param {String} [options.host] The hostname where to bind the server
+   * @param {Number} [options.maxPayload=104857600] The maximum allowed message
+   *     size
+   * @param {Boolean} [options.noServer=false] Enable no server mode
+   * @param {String} [options.path] Accept only connections matching this path
+   * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
+   *     permessage-deflate
+   * @param {Number} [options.port] The port where to bind the server
+   * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
+   *     server to use
+   * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+   *     not to skip UTF-8 validation for text and close messages
+   * @param {Function} [options.verifyClient] A hook to reject connections
+   * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
+   *     class to use. It must be the `WebSocket` class or class that extends it
+   * @param {Function} [callback] A listener for the `listening` event
+   */
+  constructor(options, callback) {
+    super();
+
+    options = {
+      allowSynchronousEvents: true,
+      autoPong: true,
+      maxPayload: 100 * 1024 * 1024,
+      skipUTF8Validation: false,
+      perMessageDeflate: false,
+      handleProtocols: null,
+      clientTracking: true,
+      closeTimeout: CLOSE_TIMEOUT,
+      verifyClient: null,
+      noServer: false,
+      backlog: null, // use default (511 as implemented in net.js)
+      server: null,
+      host: null,
+      path: null,
+      port: null,
+      WebSocket,
+      ...options
+    };
+
+    if (
+      (options.port == null && !options.server && !options.noServer) ||
+      (options.port != null && (options.server || options.noServer)) ||
+      (options.server && options.noServer)
+    ) {
+      throw new TypeError(
+        'One and only one of the "port", "server", or "noServer" options ' +
+          'must be specified'
+      );
+    }
+
+    if (options.port != null) {
+      this._server = http.createServer((req, res) => {
+        const body = http.STATUS_CODES[426];
+
+        res.writeHead(426, {
+          'Content-Length': body.length,
+          'Content-Type': 'text/plain'
+        });
+        res.end(body);
+      });
+      this._server.listen(
+        options.port,
+        options.host,
+        options.backlog,
+        callback
+      );
+    } else if (options.server) {
+      this._server = options.server;
+    }
+
+    if (this._server) {
+      const emitConnection = this.emit.bind(this, 'connection');
+
+      this._removeListeners = addListeners(this._server, {
+        listening: this.emit.bind(this, 'listening'),
+        error: this.emit.bind(this, 'error'),
+        upgrade: (req, socket, head) => {
+          this.handleUpgrade(req, socket, head, emitConnection);
+        }
+      });
+    }
+
+    if (options.perMessageDeflate === true) options.perMessageDeflate = {};
+    if (options.clientTracking) {
+      this.clients = new Set();
+      this._shouldEmitClose = false;
+    }
+
+    this.options = options;
+    this._state = RUNNING;
+  }
+
+  /**
+   * Returns the bound address, the address family name, and port of the server
+   * as reported by the operating system if listening on an IP socket.
+   * If the server is listening on a pipe or UNIX domain socket, the name is
+   * returned as a string.
+   *
+   * @return {(Object|String|null)} The address of the server
+   * @public
+   */
+  address() {
+    if (this.options.noServer) {
+      throw new Error('The server is operating in "noServer" mode');
+    }
+
+    if (!this._server) return null;
+    return this._server.address();
+  }
+
+  /**
+   * Stop the server from accepting new connections and emit the `'close'` event
+   * when all existing connections are closed.
+   *
+   * @param {Function} [cb] A one-time listener for the `'close'` event
+   * @public
+   */
+  close(cb) {
+    if (this._state === CLOSED) {
+      if (cb) {
+        this.once('close', () => {
+          cb(new Error('The server is not running'));
+        });
+      }
+
+      process.nextTick(emitClose, this);
+      return;
+    }
+
+    if (cb) this.once('close', cb);
+
+    if (this._state === CLOSING) return;
+    this._state = CLOSING;
+
+    if (this.options.noServer || this.options.server) {
+      if (this._server) {
+        this._removeListeners();
+        this._removeListeners = this._server = null;
+      }
+
+      if (this.clients) {
+        if (!this.clients.size) {
+          process.nextTick(emitClose, this);
+        } else {
+          this._shouldEmitClose = true;
+        }
+      } else {
+        process.nextTick(emitClose, this);
+      }
+    } else {
+      const server = this._server;
+
+      this._removeListeners();
+      this._removeListeners = this._server = null;
+
+      //
+      // The HTTP/S server was created internally. Close it, and rely on its
+      // `'close'` event.
+      //
+      server.close(() => {
+        emitClose(this);
+      });
+    }
+  }
+
+  /**
+   * See if a given request should be handled by this server instance.
+   *
+   * @param {http.IncomingMessage} req Request object to inspect
+   * @return {Boolean} `true` if the request is valid, else `false`
+   * @public
+   */
+  shouldHandle(req) {
+    if (this.options.path) {
+      const index = req.url.indexOf('?');
+      const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
+
+      if (pathname !== this.options.path) return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Handle a HTTP Upgrade request.
+   *
+   * @param {http.IncomingMessage} req The request object
+   * @param {Duplex} socket The network socket between the server and client
+   * @param {Buffer} head The first packet of the upgraded stream
+   * @param {Function} cb Callback
+   * @public
+   */
+  handleUpgrade(req, socket, head, cb) {
+    socket.on('error', socketOnError);
+
+    const key = req.headers['sec-websocket-key'];
+    const upgrade = req.headers.upgrade;
+    const version = +req.headers['sec-websocket-version'];
+
+    if (req.method !== 'GET') {
+      const message = 'Invalid HTTP method';
+      abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
+      return;
+    }
+
+    if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
+      const message = 'Invalid Upgrade header';
+      abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+      return;
+    }
+
+    if (key === undefined || !keyRegex.test(key)) {
+      const message = 'Missing or invalid Sec-WebSocket-Key header';
+      abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+      return;
+    }
+
+    if (version !== 13 && version !== 8) {
+      const message = 'Missing or invalid Sec-WebSocket-Version header';
+      abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {
+        'Sec-WebSocket-Version': '13, 8'
+      });
+      return;
+    }
+
+    if (!this.shouldHandle(req)) {
+      abortHandshake(socket, 400);
+      return;
+    }
+
+    const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
+    let protocols = new Set();
+
+    if (secWebSocketProtocol !== undefined) {
+      try {
+        protocols = subprotocol.parse(secWebSocketProtocol);
+      } catch (err) {
+        const message = 'Invalid Sec-WebSocket-Protocol header';
+        abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+        return;
+      }
+    }
+
+    const secWebSocketExtensions = req.headers['sec-websocket-extensions'];
+    const extensions = {};
+
+    if (
+      this.options.perMessageDeflate &&
+      secWebSocketExtensions !== undefined
+    ) {
+      const perMessageDeflate = new PerMessageDeflate({
+        ...this.options.perMessageDeflate,
+        isServer: true,
+        maxPayload: this.options.maxPayload
+      });
+
+      try {
+        const offers = extension.parse(secWebSocketExtensions);
+
+        if (offers[PerMessageDeflate.extensionName]) {
+          perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
+          extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
+        }
+      } catch (err) {
+        const message =
+          'Invalid or unacceptable Sec-WebSocket-Extensions header';
+        abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
+        return;
+      }
+    }
+
+    //
+    // Optionally call external client verification handler.
+    //
+    if (this.options.verifyClient) {
+      const info = {
+        origin:
+          req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
+        secure: !!(req.socket.authorized || req.socket.encrypted),
+        req
+      };
+
+      if (this.options.verifyClient.length === 2) {
+        this.options.verifyClient(info, (verified, code, message, headers) => {
+          if (!verified) {
+            return abortHandshake(socket, code || 401, message, headers);
+          }
+
+          this.completeUpgrade(
+            extensions,
+            key,
+            protocols,
+            req,
+            socket,
+            head,
+            cb
+          );
+        });
+        return;
+      }
+
+      if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
+    }
+
+    this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
+  }
+
+  /**
+   * Upgrade the connection to WebSocket.
+   *
+   * @param {Object} extensions The accepted extensions
+   * @param {String} key The value of the `Sec-WebSocket-Key` header
+   * @param {Set} protocols The subprotocols
+   * @param {http.IncomingMessage} req The request object
+   * @param {Duplex} socket The network socket between the server and client
+   * @param {Buffer} head The first packet of the upgraded stream
+   * @param {Function} cb Callback
+   * @throws {Error} If called more than once with the same socket
+   * @private
+   */
+  completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
+    //
+    // Destroy the socket if the client has already sent a FIN packet.
+    //
+    if (!socket.readable || !socket.writable) return socket.destroy();
+
+    if (socket[kWebSocket]) {
+      throw new Error(
+        'server.handleUpgrade() was called more than once with the same ' +
+          'socket, possibly due to a misconfiguration'
+      );
+    }
+
+    if (this._state > RUNNING) return abortHandshake(socket, 503);
+
+    const digest = createHash('sha1')
+      .update(key + GUID)
+      .digest('base64');
+
+    const headers = [
+      'HTTP/1.1 101 Switching Protocols',
+      'Upgrade: websocket',
+      'Connection: Upgrade',
+      `Sec-WebSocket-Accept: ${digest}`
+    ];
+
+    const ws = new this.options.WebSocket(null, undefined, this.options);
+
+    if (protocols.size) {
+      //
+      // Optionally call external protocol selection handler.
+      //
+      const protocol = this.options.handleProtocols
+        ? this.options.handleProtocols(protocols, req)
+        : protocols.values().next().value;
+
+      if (protocol) {
+        headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
+        ws._protocol = protocol;
+      }
+    }
+
+    if (extensions[PerMessageDeflate.extensionName]) {
+      const params = extensions[PerMessageDeflate.extensionName].params;
+      const value = extension.format({
+        [PerMessageDeflate.extensionName]: [params]
+      });
+      headers.push(`Sec-WebSocket-Extensions: ${value}`);
+      ws._extensions = extensions;
+    }
+
+    //
+    // Allow external modification/inspection of handshake headers.
+    //
+    this.emit('headers', headers, req);
+
+    socket.write(headers.concat('\r\n').join('\r\n'));
+    socket.removeListener('error', socketOnError);
+
+    ws.setSocket(socket, head, {
+      allowSynchronousEvents: this.options.allowSynchronousEvents,
+      maxPayload: this.options.maxPayload,
+      skipUTF8Validation: this.options.skipUTF8Validation
+    });
+
+    if (this.clients) {
+      this.clients.add(ws);
+      ws.on('close', () => {
+        this.clients.delete(ws);
+
+        if (this._shouldEmitClose && !this.clients.size) {
+          process.nextTick(emitClose, this);
+        }
+      });
+    }
+
+    cb(ws, req);
+  }
+}
+
+module.exports = WebSocketServer;
+
+/**
+ * Add event listeners on an `EventEmitter` using a map of <event, listener>
+ * pairs.
+ *
+ * @param {EventEmitter} server The event emitter
+ * @param {Object.<String, Function>} map The listeners to add
+ * @return {Function} A function that will remove the added listeners when
+ *     called
+ * @private
+ */
+function addListeners(server, map) {
+  for (const event of Object.keys(map)) server.on(event, map[event]);
+
+  return function removeListeners() {
+    for (const event of Object.keys(map)) {
+      server.removeListener(event, map[event]);
+    }
+  };
+}
+
+/**
+ * Emit a `'close'` event on an `EventEmitter`.
+ *
+ * @param {EventEmitter} server The event emitter
+ * @private
+ */
+function emitClose(server) {
+  server._state = CLOSED;
+  server.emit('close');
+}
+
+/**
+ * Handle socket errors.
+ *
+ * @private
+ */
+function socketOnError() {
+  this.destroy();
+}
+
+/**
+ * Close the connection when preconditions are not fulfilled.
+ *
+ * @param {Duplex} socket The socket of the upgrade request
+ * @param {Number} code The HTTP response status code
+ * @param {String} [message] The HTTP response body
+ * @param {Object} [headers] Additional HTTP response headers
+ * @private
+ */
+function abortHandshake(socket, code, message, headers) {
+  //
+  // The socket is writable unless the user destroyed or ended it before calling
+  // `server.handleUpgrade()` or in the `verifyClient` function, which is a user
+  // error. Handling this does not make much sense as the worst that can happen
+  // is that some of the data written by the user might be discarded due to the
+  // call to `socket.end()` below, which triggers an `'error'` event that in
+  // turn causes the socket to be destroyed.
+  //
+  message = message || http.STATUS_CODES[code];
+  headers = {
+    Connection: 'close',
+    'Content-Type': 'text/html',
+    'Content-Length': Buffer.byteLength(message),
+    ...headers
+  };
+
+  socket.once('finish', socket.destroy);
+
+  socket.end(
+    `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
+      Object.keys(headers)
+        .map((h) => `${h}: ${headers[h]}`)
+        .join('\r\n') +
+      '\r\n\r\n' +
+      message
+  );
+}
+
+/**
+ * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
+ * one listener for it, otherwise call `abortHandshake()`.
+ *
+ * @param {WebSocketServer} server The WebSocket server
+ * @param {http.IncomingMessage} req The request object
+ * @param {Duplex} socket The socket of the upgrade request
+ * @param {Number} code The HTTP response status code
+ * @param {String} message The HTTP response body
+ * @param {Object} [headers] The HTTP response headers
+ * @private
+ */
+function abortHandshakeOrEmitwsClientError(
+  server,
+  req,
+  socket,
+  code,
+  message,
+  headers
+) {
+  if (server.listenerCount('wsClientError')) {
+    const err = new Error(message);
+    Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
+
+    server.emit('wsClientError', err, socket, req);
+  } else {
+    abortHandshake(socket, code, message, headers);
+  }
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/lib/websocket.js
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/lib/websocket.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/lib/websocket.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1393 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$", "caughtErrors": "none" }] */
+
+'use strict';
+
+const EventEmitter = require('events');
+const https = require('https');
+const http = require('http');
+const net = require('net');
+const tls = require('tls');
+const { randomBytes, createHash } = require('crypto');
+const { Duplex, Readable } = require('stream');
+const { URL } = require('url');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const Receiver = require('./receiver');
+const Sender = require('./sender');
+const { isBlob } = require('./validation');
+
+const {
+  BINARY_TYPES,
+  CLOSE_TIMEOUT,
+  EMPTY_BUFFER,
+  GUID,
+  kForOnEventAttribute,
+  kListener,
+  kStatusCode,
+  kWebSocket,
+  NOOP
+} = require('./constants');
+const {
+  EventTarget: { addEventListener, removeEventListener }
+} = require('./event-target');
+const { format, parse } = require('./extension');
+const { toBuffer } = require('./buffer-util');
+
+const kAborted = Symbol('kAborted');
+const protocolVersions = [8, 13];
+const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
+const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
+
+/**
+ * Class representing a WebSocket.
+ *
+ * @extends EventEmitter
+ */
+class WebSocket extends EventEmitter {
+  /**
+   * Create a new `WebSocket`.
+   *
+   * @param {(String|URL)} address The URL to which to connect
+   * @param {(String|String[])} [protocols] The subprotocols
+   * @param {Object} [options] Connection options
+   */
+  constructor(address, protocols, options) {
+    super();
+
+    this._binaryType = BINARY_TYPES[0];
+    this._closeCode = 1006;
+    this._closeFrameReceived = false;
+    this._closeFrameSent = false;
+    this._closeMessage = EMPTY_BUFFER;
+    this._closeTimer = null;
+    this._errorEmitted = false;
+    this._extensions = {};
+    this._paused = false;
+    this._protocol = '';
+    this._readyState = WebSocket.CONNECTING;
+    this._receiver = null;
+    this._sender = null;
+    this._socket = null;
+
+    if (address !== null) {
+      this._bufferedAmount = 0;
+      this._isServer = false;
+      this._redirects = 0;
+
+      if (protocols === undefined) {
+        protocols = [];
+      } else if (!Array.isArray(protocols)) {
+        if (typeof protocols === 'object' && protocols !== null) {
+          options = protocols;
+          protocols = [];
+        } else {
+          protocols = [protocols];
+        }
+      }
+
+      initAsClient(this, address, protocols, options);
+    } else {
+      this._autoPong = options.autoPong;
+      this._closeTimeout = options.closeTimeout;
+      this._isServer = true;
+    }
+  }
+
+  /**
+   * For historical reasons, the custom "nodebuffer" type is used by the default
+   * instead of "blob".
+   *
+   * @type {String}
+   */
+  get binaryType() {
+    return this._binaryType;
+  }
+
+  set binaryType(type) {
+    if (!BINARY_TYPES.includes(type)) return;
+
+    this._binaryType = type;
+
+    //
+    // Allow to change `binaryType` on the fly.
+    //
+    if (this._receiver) this._receiver._binaryType = type;
+  }
+
+  /**
+   * @type {Number}
+   */
+  get bufferedAmount() {
+    if (!this._socket) return this._bufferedAmount;
+
+    return this._socket._writableState.length + this._sender._bufferedBytes;
+  }
+
+  /**
+   * @type {String}
+   */
+  get extensions() {
+    return Object.keys(this._extensions).join();
+  }
+
+  /**
+   * @type {Boolean}
+   */
+  get isPaused() {
+    return this._paused;
+  }
+
+  /**
+   * @type {Function}
+   */
+  /* istanbul ignore next */
+  get onclose() {
+    return null;
+  }
+
+  /**
+   * @type {Function}
+   */
+  /* istanbul ignore next */
+  get onerror() {
+    return null;
+  }
+
+  /**
+   * @type {Function}
+   */
+  /* istanbul ignore next */
+  get onopen() {
+    return null;
+  }
+
+  /**
+   * @type {Function}
+   */
+  /* istanbul ignore next */
+  get onmessage() {
+    return null;
+  }
+
+  /**
+   * @type {String}
+   */
+  get protocol() {
+    return this._protocol;
+  }
+
+  /**
+   * @type {Number}
+   */
+  get readyState() {
+    return this._readyState;
+  }
+
+  /**
+   * @type {String}
+   */
+  get url() {
+    return this._url;
+  }
+
+  /**
+   * Set up the socket and the internal resources.
+   *
+   * @param {Duplex} socket The network socket between the server and client
+   * @param {Buffer} head The first packet of the upgraded stream
+   * @param {Object} options Options object
+   * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
+   *     any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
+   *     multiple times in the same tick
+   * @param {Function} [options.generateMask] The function used to generate the
+   *     masking key
+   * @param {Number} [options.maxPayload=0] The maximum allowed message size
+   * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+   *     not to skip UTF-8 validation for text and close messages
+   * @private
+   */
+  setSocket(socket, head, options) {
+    const receiver = new Receiver({
+      allowSynchronousEvents: options.allowSynchronousEvents,
+      binaryType: this.binaryType,
+      extensions: this._extensions,
+      isServer: this._isServer,
+      maxPayload: options.maxPayload,
+      skipUTF8Validation: options.skipUTF8Validation
+    });
+
+    const sender = new Sender(socket, this._extensions, options.generateMask);
+
+    this._receiver = receiver;
+    this._sender = sender;
+    this._socket = socket;
+
+    receiver[kWebSocket] = this;
+    sender[kWebSocket] = this;
+    socket[kWebSocket] = this;
+
+    receiver.on('conclude', receiverOnConclude);
+    receiver.on('drain', receiverOnDrain);
+    receiver.on('error', receiverOnError);
+    receiver.on('message', receiverOnMessage);
+    receiver.on('ping', receiverOnPing);
+    receiver.on('pong', receiverOnPong);
+
+    sender.onerror = senderOnError;
+
+    //
+    // These methods may not be available if `socket` is just a `Duplex`.
+    //
+    if (socket.setTimeout) socket.setTimeout(0);
+    if (socket.setNoDelay) socket.setNoDelay();
+
+    if (head.length > 0) socket.unshift(head);
+
+    socket.on('close', socketOnClose);
+    socket.on('data', socketOnData);
+    socket.on('end', socketOnEnd);
+    socket.on('error', socketOnError);
+
+    this._readyState = WebSocket.OPEN;
+    this.emit('open');
+  }
+
+  /**
+   * Emit the `'close'` event.
+   *
+   * @private
+   */
+  emitClose() {
+    if (!this._socket) {
+      this._readyState = WebSocket.CLOSED;
+      this.emit('close', this._closeCode, this._closeMessage);
+      return;
+    }
+
+    if (this._extensions[PerMessageDeflate.extensionName]) {
+      this._extensions[PerMessageDeflate.extensionName].cleanup();
+    }
+
+    this._receiver.removeAllListeners();
+    this._readyState = WebSocket.CLOSED;
+    this.emit('close', this._closeCode, this._closeMessage);
+  }
+
+  /**
+   * Start a closing handshake.
+   *
+   *          +----------+   +-----------+   +----------+
+   *     - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
+   *    |     +----------+   +-----------+   +----------+     |
+   *          +----------+   +-----------+         |
+   * CLOSING  |ws.close()|<--|close frame|<--+-----+       CLOSING
+   *          +----------+   +-----------+   |
+   *    |           |                        |   +---+        |
+   *                +------------------------+-->|fin| - - - -
+   *    |         +---+                      |   +---+
+   *     - - - - -|fin|<---------------------+
+   *              +---+
+   *
+   * @param {Number} [code] Status code explaining why the connection is closing
+   * @param {(String|Buffer)} [data] The reason why the connection is
+   *     closing
+   * @public
+   */
+  close(code, data) {
+    if (this.readyState === WebSocket.CLOSED) return;
+    if (this.readyState === WebSocket.CONNECTING) {
+      const msg = 'WebSocket was closed before the connection was established';
+      abortHandshake(this, this._req, msg);
+      return;
+    }
+
+    if (this.readyState === WebSocket.CLOSING) {
+      if (
+        this._closeFrameSent &&
+        (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
+      ) {
+        this._socket.end();
+      }
+
+      return;
+    }
+
+    this._readyState = WebSocket.CLOSING;
+    this._sender.close(code, data, !this._isServer, (err) => {
+      //
+      // This error is handled by the `'error'` listener on the socket. We only
+      // want to know if the close frame has been sent here.
+      //
+      if (err) return;
+
+      this._closeFrameSent = true;
+
+      if (
+        this._closeFrameReceived ||
+        this._receiver._writableState.errorEmitted
+      ) {
+        this._socket.end();
+      }
+    });
+
+    setCloseTimer(this);
+  }
+
+  /**
+   * Pause the socket.
+   *
+   * @public
+   */
+  pause() {
+    if (
+      this.readyState === WebSocket.CONNECTING ||
+      this.readyState === WebSocket.CLOSED
+    ) {
+      return;
+    }
+
+    this._paused = true;
+    this._socket.pause();
+  }
+
+  /**
+   * Send a ping.
+   *
+   * @param {*} [data] The data to send
+   * @param {Boolean} [mask] Indicates whether or not to mask `data`
+   * @param {Function} [cb] Callback which is executed when the ping is sent
+   * @public
+   */
+  ping(data, mask, cb) {
+    if (this.readyState === WebSocket.CONNECTING) {
+      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
+    }
+
+    if (typeof data === 'function') {
+      cb = data;
+      data = mask = undefined;
+    } else if (typeof mask === 'function') {
+      cb = mask;
+      mask = undefined;
+    }
+
+    if (typeof data === 'number') data = data.toString();
+
+    if (this.readyState !== WebSocket.OPEN) {
+      sendAfterClose(this, data, cb);
+      return;
+    }
+
+    if (mask === undefined) mask = !this._isServer;
+    this._sender.ping(data || EMPTY_BUFFER, mask, cb);
+  }
+
+  /**
+   * Send a pong.
+   *
+   * @param {*} [data] The data to send
+   * @param {Boolean} [mask] Indicates whether or not to mask `data`
+   * @param {Function} [cb] Callback which is executed when the pong is sent
+   * @public
+   */
+  pong(data, mask, cb) {
+    if (this.readyState === WebSocket.CONNECTING) {
+      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
+    }
+
+    if (typeof data === 'function') {
+      cb = data;
+      data = mask = undefined;
+    } else if (typeof mask === 'function') {
+      cb = mask;
+      mask = undefined;
+    }
+
+    if (typeof data === 'number') data = data.toString();
+
+    if (this.readyState !== WebSocket.OPEN) {
+      sendAfterClose(this, data, cb);
+      return;
+    }
+
+    if (mask === undefined) mask = !this._isServer;
+    this._sender.pong(data || EMPTY_BUFFER, mask, cb);
+  }
+
+  /**
+   * Resume the socket.
+   *
+   * @public
+   */
+  resume() {
+    if (
+      this.readyState === WebSocket.CONNECTING ||
+      this.readyState === WebSocket.CLOSED
+    ) {
+      return;
+    }
+
+    this._paused = false;
+    if (!this._receiver._writableState.needDrain) this._socket.resume();
+  }
+
+  /**
+   * Send a data message.
+   *
+   * @param {*} data The message to send
+   * @param {Object} [options] Options object
+   * @param {Boolean} [options.binary] Specifies whether `data` is binary or
+   *     text
+   * @param {Boolean} [options.compress] Specifies whether or not to compress
+   *     `data`
+   * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
+   *     last one
+   * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
+   * @param {Function} [cb] Callback which is executed when data is written out
+   * @public
+   */
+  send(data, options, cb) {
+    if (this.readyState === WebSocket.CONNECTING) {
+      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
+    }
+
+    if (typeof options === 'function') {
+      cb = options;
+      options = {};
+    }
+
+    if (typeof data === 'number') data = data.toString();
+
+    if (this.readyState !== WebSocket.OPEN) {
+      sendAfterClose(this, data, cb);
+      return;
+    }
+
+    const opts = {
+      binary: typeof data !== 'string',
+      mask: !this._isServer,
+      compress: true,
+      fin: true,
+      ...options
+    };
+
+    if (!this._extensions[PerMessageDeflate.extensionName]) {
+      opts.compress = false;
+    }
+
+    this._sender.send(data || EMPTY_BUFFER, opts, cb);
+  }
+
+  /**
+   * Forcibly close the connection.
+   *
+   * @public
+   */
+  terminate() {
+    if (this.readyState === WebSocket.CLOSED) return;
+    if (this.readyState === WebSocket.CONNECTING) {
+      const msg = 'WebSocket was closed before the connection was established';
+      abortHandshake(this, this._req, msg);
+      return;
+    }
+
+    if (this._socket) {
+      this._readyState = WebSocket.CLOSING;
+      this._socket.destroy();
+    }
+  }
+}
+
+/**
+ * @constant {Number} CONNECTING
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'CONNECTING', {
+  enumerable: true,
+  value: readyStates.indexOf('CONNECTING')
+});
+
+/**
+ * @constant {Number} CONNECTING
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'CONNECTING', {
+  enumerable: true,
+  value: readyStates.indexOf('CONNECTING')
+});
+
+/**
+ * @constant {Number} OPEN
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'OPEN', {
+  enumerable: true,
+  value: readyStates.indexOf('OPEN')
+});
+
+/**
+ * @constant {Number} OPEN
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'OPEN', {
+  enumerable: true,
+  value: readyStates.indexOf('OPEN')
+});
+
+/**
+ * @constant {Number} CLOSING
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'CLOSING', {
+  enumerable: true,
+  value: readyStates.indexOf('CLOSING')
+});
+
+/**
+ * @constant {Number} CLOSING
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'CLOSING', {
+  enumerable: true,
+  value: readyStates.indexOf('CLOSING')
+});
+
+/**
+ * @constant {Number} CLOSED
+ * @memberof WebSocket
+ */
+Object.defineProperty(WebSocket, 'CLOSED', {
+  enumerable: true,
+  value: readyStates.indexOf('CLOSED')
+});
+
+/**
+ * @constant {Number} CLOSED
+ * @memberof WebSocket.prototype
+ */
+Object.defineProperty(WebSocket.prototype, 'CLOSED', {
+  enumerable: true,
+  value: readyStates.indexOf('CLOSED')
+});
+
+[
+  'binaryType',
+  'bufferedAmount',
+  'extensions',
+  'isPaused',
+  'protocol',
+  'readyState',
+  'url'
+].forEach((property) => {
+  Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
+});
+
+//
+// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
+// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
+//
+['open', 'error', 'close', 'message'].forEach((method) => {
+  Object.defineProperty(WebSocket.prototype, `on${method}`, {
+    enumerable: true,
+    get() {
+      for (const listener of this.listeners(method)) {
+        if (listener[kForOnEventAttribute]) return listener[kListener];
+      }
+
+      return null;
+    },
+    set(handler) {
+      for (const listener of this.listeners(method)) {
+        if (listener[kForOnEventAttribute]) {
+          this.removeListener(method, listener);
+          break;
+        }
+      }
+
+      if (typeof handler !== 'function') return;
+
+      this.addEventListener(method, handler, {
+        [kForOnEventAttribute]: true
+      });
+    }
+  });
+});
+
+WebSocket.prototype.addEventListener = addEventListener;
+WebSocket.prototype.removeEventListener = removeEventListener;
+
+module.exports = WebSocket;
+
+/**
+ * Initialize a WebSocket client.
+ *
+ * @param {WebSocket} websocket The client to initialize
+ * @param {(String|URL)} address The URL to which to connect
+ * @param {Array} protocols The subprotocols
+ * @param {Object} [options] Connection options
+ * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any
+ *     of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
+ *     times in the same tick
+ * @param {Boolean} [options.autoPong=true] Specifies whether or not to
+ *     automatically send a pong in response to a ping
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait
+ *     for the closing handshake to finish after `websocket.close()` is called
+ * @param {Function} [options.finishRequest] A function which can be used to
+ *     customize the headers of each http request before it is sent
+ * @param {Boolean} [options.followRedirects=false] Whether or not to follow
+ *     redirects
+ * @param {Function} [options.generateMask] The function used to generate the
+ *     masking key
+ * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
+ *     handshake request
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
+ *     size
+ * @param {Number} [options.maxRedirects=10] The maximum number of redirects
+ *     allowed
+ * @param {String} [options.origin] Value of the `Origin` or
+ *     `Sec-WebSocket-Origin` header
+ * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
+ *     permessage-deflate
+ * @param {Number} [options.protocolVersion=13] Value of the
+ *     `Sec-WebSocket-Version` header
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
+ *     not to skip UTF-8 validation for text and close messages
+ * @private
+ */
+function initAsClient(websocket, address, protocols, options) {
+  const opts = {
+    allowSynchronousEvents: true,
+    autoPong: true,
+    closeTimeout: CLOSE_TIMEOUT,
+    protocolVersion: protocolVersions[1],
+    maxPayload: 100 * 1024 * 1024,
+    skipUTF8Validation: false,
+    perMessageDeflate: true,
+    followRedirects: false,
+    maxRedirects: 10,
+    ...options,
+    socketPath: undefined,
+    hostname: undefined,
+    protocol: undefined,
+    timeout: undefined,
+    method: 'GET',
+    host: undefined,
+    path: undefined,
+    port: undefined
+  };
+
+  websocket._autoPong = opts.autoPong;
+  websocket._closeTimeout = opts.closeTimeout;
+
+  if (!protocolVersions.includes(opts.protocolVersion)) {
+    throw new RangeError(
+      `Unsupported protocol version: ${opts.protocolVersion} ` +
+        `(supported versions: ${protocolVersions.join(', ')})`
+    );
+  }
+
+  let parsedUrl;
+
+  if (address instanceof URL) {
+    parsedUrl = address;
+  } else {
+    try {
+      parsedUrl = new URL(address);
+    } catch {
+      throw new SyntaxError(`Invalid URL: ${address}`);
+    }
+  }
+
+  if (parsedUrl.protocol === 'http:') {
+    parsedUrl.protocol = 'ws:';
+  } else if (parsedUrl.protocol === 'https:') {
+    parsedUrl.protocol = 'wss:';
+  }
+
+  websocket._url = parsedUrl.href;
+
+  const isSecure = parsedUrl.protocol === 'wss:';
+  const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
+  let invalidUrlMessage;
+
+  if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
+    invalidUrlMessage =
+      'The URL\'s protocol must be one of "ws:", "wss:", ' +
+      '"http:", "https:", or "ws+unix:"';
+  } else if (isIpcUrl && !parsedUrl.pathname) {
+    invalidUrlMessage = "The URL's pathname is empty";
+  } else if (parsedUrl.hash) {
+    invalidUrlMessage = 'The URL contains a fragment identifier';
+  }
+
+  if (invalidUrlMessage) {
+    const err = new SyntaxError(invalidUrlMessage);
+
+    if (websocket._redirects === 0) {
+      throw err;
+    } else {
+      emitErrorAndClose(websocket, err);
+      return;
+    }
+  }
+
+  const defaultPort = isSecure ? 443 : 80;
+  const key = randomBytes(16).toString('base64');
+  const request = isSecure ? https.request : http.request;
+  const protocolSet = new Set();
+  let perMessageDeflate;
+
+  opts.createConnection =
+    opts.createConnection || (isSecure ? tlsConnect : netConnect);
+  opts.defaultPort = opts.defaultPort || defaultPort;
+  opts.port = parsedUrl.port || defaultPort;
+  opts.host = parsedUrl.hostname.startsWith('[')
+    ? parsedUrl.hostname.slice(1, -1)
+    : parsedUrl.hostname;
+  opts.headers = {
+    ...opts.headers,
+    'Sec-WebSocket-Version': opts.protocolVersion,
+    'Sec-WebSocket-Key': key,
+    Connection: 'Upgrade',
+    Upgrade: 'websocket'
+  };
+  opts.path = parsedUrl.pathname + parsedUrl.search;
+  opts.timeout = opts.handshakeTimeout;
+
+  if (opts.perMessageDeflate) {
+    perMessageDeflate = new PerMessageDeflate({
+      ...opts.perMessageDeflate,
+      isServer: false,
+      maxPayload: opts.maxPayload
+    });
+    opts.headers['Sec-WebSocket-Extensions'] = format({
+      [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
+    });
+  }
+  if (protocols.length) {
+    for (const protocol of protocols) {
+      if (
+        typeof protocol !== 'string' ||
+        !subprotocolRegex.test(protocol) ||
+        protocolSet.has(protocol)
+      ) {
+        throw new SyntaxError(
+          'An invalid or duplicated subprotocol was specified'
+        );
+      }
+
+      protocolSet.add(protocol);
+    }
+
+    opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');
+  }
+  if (opts.origin) {
+    if (opts.protocolVersion < 13) {
+      opts.headers['Sec-WebSocket-Origin'] = opts.origin;
+    } else {
+      opts.headers.Origin = opts.origin;
+    }
+  }
+  if (parsedUrl.username || parsedUrl.password) {
+    opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
+  }
+
+  if (isIpcUrl) {
+    const parts = opts.path.split(':');
+
+    opts.socketPath = parts[0];
+    opts.path = parts[1];
+  }
+
+  let req;
+
+  if (opts.followRedirects) {
+    if (websocket._redirects === 0) {
+      websocket._originalIpc = isIpcUrl;
+      websocket._originalSecure = isSecure;
+      websocket._originalHostOrSocketPath = isIpcUrl
+        ? opts.socketPath
+        : parsedUrl.host;
+
+      const headers = options && options.headers;
+
+      //
+      // Shallow copy the user provided options so that headers can be changed
+      // without mutating the original object.
+      //
+      options = { ...options, headers: {} };
+
+      if (headers) {
+        for (const [key, value] of Object.entries(headers)) {
+          options.headers[key.toLowerCase()] = value;
+        }
+      }
+    } else if (websocket.listenerCount('redirect') === 0) {
+      const isSameHost = isIpcUrl
+        ? websocket._originalIpc
+          ? opts.socketPath === websocket._originalHostOrSocketPath
+          : false
+        : websocket._originalIpc
+          ? false
+          : parsedUrl.host === websocket._originalHostOrSocketPath;
+
+      if (!isSameHost || (websocket._originalSecure && !isSecure)) {
+        //
+        // Match curl 7.77.0 behavior and drop the following headers. These
+        // headers are also dropped when following a redirect to a subdomain.
+        //
+        delete opts.headers.authorization;
+        delete opts.headers.cookie;
+
+        if (!isSameHost) delete opts.headers.host;
+
+        opts.auth = undefined;
+      }
+    }
+
+    //
+    // Match curl 7.77.0 behavior and make the first `Authorization` header win.
+    // If the `Authorization` header is set, then there is nothing to do as it
+    // will take precedence.
+    //
+    if (opts.auth && !options.headers.authorization) {
+      options.headers.authorization =
+        'Basic ' + Buffer.from(opts.auth).toString('base64');
+    }
+
+    req = websocket._req = request(opts);
+
+    if (websocket._redirects) {
+      //
+      // Unlike what is done for the `'upgrade'` event, no early exit is
+      // triggered here if the user calls `websocket.close()` or
+      // `websocket.terminate()` from a listener of the `'redirect'` event. This
+      // is because the user can also call `request.destroy()` with an error
+      // before calling `websocket.close()` or `websocket.terminate()` and this
+      // would result in an error being emitted on the `request` object with no
+      // `'error'` event listeners attached.
+      //
+      websocket.emit('redirect', websocket.url, req);
+    }
+  } else {
+    req = websocket._req = request(opts);
+  }
+
+  if (opts.timeout) {
+    req.on('timeout', () => {
+      abortHandshake(websocket, req, 'Opening handshake has timed out');
+    });
+  }
+
+  req.on('error', (err) => {
+    if (req === null || req[kAborted]) return;
+
+    req = websocket._req = null;
+    emitErrorAndClose(websocket, err);
+  });
+
+  req.on('response', (res) => {
+    const location = res.headers.location;
+    const statusCode = res.statusCode;
+
+    if (
+      location &&
+      opts.followRedirects &&
+      statusCode >= 300 &&
+      statusCode < 400
+    ) {
+      if (++websocket._redirects > opts.maxRedirects) {
+        abortHandshake(websocket, req, 'Maximum redirects exceeded');
+        return;
+      }
+
+      req.abort();
+
+      let addr;
+
+      try {
+        addr = new URL(location, address);
+      } catch (e) {
+        const err = new SyntaxError(`Invalid URL: ${location}`);
+        emitErrorAndClose(websocket, err);
+        return;
+      }
+
+      initAsClient(websocket, addr, protocols, options);
+    } else if (!websocket.emit('unexpected-response', req, res)) {
+      abortHandshake(
+        websocket,
+        req,
+        `Unexpected server response: ${res.statusCode}`
+      );
+    }
+  });
+
+  req.on('upgrade', (res, socket, head) => {
+    websocket.emit('upgrade', res);
+
+    //
+    // The user may have closed the connection from a listener of the
+    // `'upgrade'` event.
+    //
+    if (websocket.readyState !== WebSocket.CONNECTING) return;
+
+    req = websocket._req = null;
+
+    const upgrade = res.headers.upgrade;
+
+    if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
+      abortHandshake(websocket, socket, 'Invalid Upgrade header');
+      return;
+    }
+
+    const digest = createHash('sha1')
+      .update(key + GUID)
+      .digest('base64');
+
+    if (res.headers['sec-websocket-accept'] !== digest) {
+      abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
+      return;
+    }
+
+    const serverProt = res.headers['sec-websocket-protocol'];
+    let protError;
+
+    if (serverProt !== undefined) {
+      if (!protocolSet.size) {
+        protError = 'Server sent a subprotocol but none was requested';
+      } else if (!protocolSet.has(serverProt)) {
+        protError = 'Server sent an invalid subprotocol';
+      }
+    } else if (protocolSet.size) {
+      protError = 'Server sent no subprotocol';
+    }
+
+    if (protError) {
+      abortHandshake(websocket, socket, protError);
+      return;
+    }
+
+    if (serverProt) websocket._protocol = serverProt;
+
+    const secWebSocketExtensions = res.headers['sec-websocket-extensions'];
+
+    if (secWebSocketExtensions !== undefined) {
+      if (!perMessageDeflate) {
+        const message =
+          'Server sent a Sec-WebSocket-Extensions header but no extension ' +
+          'was requested';
+        abortHandshake(websocket, socket, message);
+        return;
+      }
+
+      let extensions;
+
+      try {
+        extensions = parse(secWebSocketExtensions);
+      } catch (err) {
+        const message = 'Invalid Sec-WebSocket-Extensions header';
+        abortHandshake(websocket, socket, message);
+        return;
+      }
+
+      const extensionNames = Object.keys(extensions);
+
+      if (
+        extensionNames.length !== 1 ||
+        extensionNames[0] !== PerMessageDeflate.extensionName
+      ) {
+        const message = 'Server indicated an extension that was not requested';
+        abortHandshake(websocket, socket, message);
+        return;
+      }
+
+      try {
+        perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
+      } catch (err) {
+        const message = 'Invalid Sec-WebSocket-Extensions header';
+        abortHandshake(websocket, socket, message);
+        return;
+      }
+
+      websocket._extensions[PerMessageDeflate.extensionName] =
+        perMessageDeflate;
+    }
+
+    websocket.setSocket(socket, head, {
+      allowSynchronousEvents: opts.allowSynchronousEvents,
+      generateMask: opts.generateMask,
+      maxPayload: opts.maxPayload,
+      skipUTF8Validation: opts.skipUTF8Validation
+    });
+  });
+
+  if (opts.finishRequest) {
+    opts.finishRequest(req, websocket);
+  } else {
+    req.end();
+  }
+}
+
+/**
+ * Emit the `'error'` and `'close'` events.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {Error} The error to emit
+ * @private
+ */
+function emitErrorAndClose(websocket, err) {
+  websocket._readyState = WebSocket.CLOSING;
+  //
+  // The following assignment is practically useless and is done only for
+  // consistency.
+  //
+  websocket._errorEmitted = true;
+  websocket.emit('error', err);
+  websocket.emitClose();
+}
+
+/**
+ * Create a `net.Socket` and initiate a connection.
+ *
+ * @param {Object} options Connection options
+ * @return {net.Socket} The newly created socket used to start the connection
+ * @private
+ */
+function netConnect(options) {
+  options.path = options.socketPath;
+  return net.connect(options);
+}
+
+/**
+ * Create a `tls.TLSSocket` and initiate a connection.
+ *
+ * @param {Object} options Connection options
+ * @return {tls.TLSSocket} The newly created socket used to start the connection
+ * @private
+ */
+function tlsConnect(options) {
+  options.path = undefined;
+
+  if (!options.servername && options.servername !== '') {
+    options.servername = net.isIP(options.host) ? '' : options.host;
+  }
+
+  return tls.connect(options);
+}
+
+/**
+ * Abort the handshake and emit an error.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
+ *     abort or the socket to destroy
+ * @param {String} message The error message
+ * @private
+ */
+function abortHandshake(websocket, stream, message) {
+  websocket._readyState = WebSocket.CLOSING;
+
+  const err = new Error(message);
+  Error.captureStackTrace(err, abortHandshake);
+
+  if (stream.setHeader) {
+    stream[kAborted] = true;
+    stream.abort();
+
+    if (stream.socket && !stream.socket.destroyed) {
+      //
+      // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if
+      // called after the request completed. See
+      // https://github.com/websockets/ws/issues/1869.
+      //
+      stream.socket.destroy();
+    }
+
+    process.nextTick(emitErrorAndClose, websocket, err);
+  } else {
+    stream.destroy(err);
+    stream.once('error', websocket.emit.bind(websocket, 'error'));
+    stream.once('close', websocket.emitClose.bind(websocket));
+  }
+}
+
+/**
+ * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
+ * when the `readyState` attribute is `CLOSING` or `CLOSED`.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {*} [data] The data to send
+ * @param {Function} [cb] Callback
+ * @private
+ */
+function sendAfterClose(websocket, data, cb) {
+  if (data) {
+    const length = isBlob(data) ? data.size : toBuffer(data).length;
+
+    //
+    // The `_bufferedAmount` property is used only when the peer is a client and
+    // the opening handshake fails. Under these circumstances, in fact, the
+    // `setSocket()` method is not called, so the `_socket` and `_sender`
+    // properties are set to `null`.
+    //
+    if (websocket._socket) websocket._sender._bufferedBytes += length;
+    else websocket._bufferedAmount += length;
+  }
+
+  if (cb) {
+    const err = new Error(
+      `WebSocket is not open: readyState ${websocket.readyState} ` +
+        `(${readyStates[websocket.readyState]})`
+    );
+    process.nextTick(cb, err);
+  }
+}
+
+/**
+ * The listener of the `Receiver` `'conclude'` event.
+ *
+ * @param {Number} code The status code
+ * @param {Buffer} reason The reason for closing
+ * @private
+ */
+function receiverOnConclude(code, reason) {
+  const websocket = this[kWebSocket];
+
+  websocket._closeFrameReceived = true;
+  websocket._closeMessage = reason;
+  websocket._closeCode = code;
+
+  if (websocket._socket[kWebSocket] === undefined) return;
+
+  websocket._socket.removeListener('data', socketOnData);
+  process.nextTick(resume, websocket._socket);
+
+  if (code === 1005) websocket.close();
+  else websocket.close(code, reason);
+}
+
+/**
+ * The listener of the `Receiver` `'drain'` event.
+ *
+ * @private
+ */
+function receiverOnDrain() {
+  const websocket = this[kWebSocket];
+
+  if (!websocket.isPaused) websocket._socket.resume();
+}
+
+/**
+ * The listener of the `Receiver` `'error'` event.
+ *
+ * @param {(RangeError|Error)} err The emitted error
+ * @private
+ */
+function receiverOnError(err) {
+  const websocket = this[kWebSocket];
+
+  if (websocket._socket[kWebSocket] !== undefined) {
+    websocket._socket.removeListener('data', socketOnData);
+
+    //
+    // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
+    // https://github.com/websockets/ws/issues/1940.
+    //
+    process.nextTick(resume, websocket._socket);
+
+    websocket.close(err[kStatusCode]);
+  }
+
+  if (!websocket._errorEmitted) {
+    websocket._errorEmitted = true;
+    websocket.emit('error', err);
+  }
+}
+
+/**
+ * The listener of the `Receiver` `'finish'` event.
+ *
+ * @private
+ */
+function receiverOnFinish() {
+  this[kWebSocket].emitClose();
+}
+
+/**
+ * The listener of the `Receiver` `'message'` event.
+ *
+ * @param {Buffer|ArrayBuffer|Buffer[])} data The message
+ * @param {Boolean} isBinary Specifies whether the message is binary or not
+ * @private
+ */
+function receiverOnMessage(data, isBinary) {
+  this[kWebSocket].emit('message', data, isBinary);
+}
+
+/**
+ * The listener of the `Receiver` `'ping'` event.
+ *
+ * @param {Buffer} data The data included in the ping frame
+ * @private
+ */
+function receiverOnPing(data) {
+  const websocket = this[kWebSocket];
+
+  if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
+  websocket.emit('ping', data);
+}
+
+/**
+ * The listener of the `Receiver` `'pong'` event.
+ *
+ * @param {Buffer} data The data included in the pong frame
+ * @private
+ */
+function receiverOnPong(data) {
+  this[kWebSocket].emit('pong', data);
+}
+
+/**
+ * Resume a readable stream
+ *
+ * @param {Readable} stream The readable stream
+ * @private
+ */
+function resume(stream) {
+  stream.resume();
+}
+
+/**
+ * The `Sender` error event handler.
+ *
+ * @param {Error} The error
+ * @private
+ */
+function senderOnError(err) {
+  const websocket = this[kWebSocket];
+
+  if (websocket.readyState === WebSocket.CLOSED) return;
+  if (websocket.readyState === WebSocket.OPEN) {
+    websocket._readyState = WebSocket.CLOSING;
+    setCloseTimer(websocket);
+  }
+
+  //
+  // `socket.end()` is used instead of `socket.destroy()` to allow the other
+  // peer to finish sending queued data. There is no need to set a timer here
+  // because `CLOSING` means that it is already set or not needed.
+  //
+  this._socket.end();
+
+  if (!websocket._errorEmitted) {
+    websocket._errorEmitted = true;
+    websocket.emit('error', err);
+  }
+}
+
+/**
+ * Set a timer to destroy the underlying raw socket of a WebSocket.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @private
+ */
+function setCloseTimer(websocket) {
+  websocket._closeTimer = setTimeout(
+    websocket._socket.destroy.bind(websocket._socket),
+    websocket._closeTimeout
+  );
+}
+
+/**
+ * The listener of the socket `'close'` event.
+ *
+ * @private
+ */
+function socketOnClose() {
+  const websocket = this[kWebSocket];
+
+  this.removeListener('close', socketOnClose);
+  this.removeListener('data', socketOnData);
+  this.removeListener('end', socketOnEnd);
+
+  websocket._readyState = WebSocket.CLOSING;
+
+  //
+  // The close frame might not have been received or the `'end'` event emitted,
+  // for example, if the socket was destroyed due to an error. Ensure that the
+  // `receiver` stream is closed after writing any remaining buffered data to
+  // it. If the readable side of the socket is in flowing mode then there is no
+  // buffered data as everything has been already written. If instead, the
+  // socket is paused, any possible buffered data will be read as a single
+  // chunk.
+  //
+  if (
+    !this._readableState.endEmitted &&
+    !websocket._closeFrameReceived &&
+    !websocket._receiver._writableState.errorEmitted &&
+    this._readableState.length !== 0
+  ) {
+    const chunk = this.read(this._readableState.length);
+
+    websocket._receiver.write(chunk);
+  }
+
+  websocket._receiver.end();
+
+  this[kWebSocket] = undefined;
+
+  clearTimeout(websocket._closeTimer);
+
+  if (
+    websocket._receiver._writableState.finished ||
+    websocket._receiver._writableState.errorEmitted
+  ) {
+    websocket.emitClose();
+  } else {
+    websocket._receiver.on('error', receiverOnFinish);
+    websocket._receiver.on('finish', receiverOnFinish);
+  }
+}
+
+/**
+ * The listener of the socket `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function socketOnData(chunk) {
+  if (!this[kWebSocket]._receiver.write(chunk)) {
+    this.pause();
+  }
+}
+
+/**
+ * The listener of the socket `'end'` event.
+ *
+ * @private
+ */
+function socketOnEnd() {
+  const websocket = this[kWebSocket];
+
+  websocket._readyState = WebSocket.CLOSING;
+  websocket._receiver.end();
+  this.end();
+}
+
+/**
+ * The listener of the socket `'error'` event.
+ *
+ * @private
+ */
+function socketOnError() {
+  const websocket = this[kWebSocket];
+
+  this.removeListener('error', socketOnError);
+  this.on('error', NOOP);
+
+  if (websocket) {
+    websocket._readyState = WebSocket.CLOSING;
+    this.destroy();
+  }
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/package.json
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,70 @@
+{
+  "name": "ws",
+  "version": "8.20.1",
+  "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
+  "keywords": [
+    "HyBi",
+    "Push",
+    "RFC-6455",
+    "WebSocket",
+    "WebSockets",
+    "real-time"
+  ],
+  "homepage": "https://github.com/websockets/ws",
+  "bugs": "https://github.com/websockets/ws/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/websockets/ws.git"
+  },
+  "author": "Einar Otto Stangvik <einaros@gmail.com> (http://2x.io)",
+  "license": "MIT",
+  "main": "index.js",
+  "exports": {
+    ".": {
+      "browser": "./browser.js",
+      "import": "./wrapper.mjs",
+      "require": "./index.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "browser": "browser.js",
+  "engines": {
+    "node": ">=10.0.0"
+  },
+  "files": [
+    "browser.js",
+    "index.js",
+    "lib/*.js",
+    "wrapper.mjs"
+  ],
+  "scripts": {
+    "test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js",
+    "integration": "mocha --throw-deprecation test/*.integration.js",
+    "lint": "eslint . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\""
+  },
+  "peerDependencies": {
+    "bufferutil": "^4.0.1",
+    "utf-8-validate": ">=5.0.2"
+  },
+  "peerDependenciesMeta": {
+    "bufferutil": {
+      "optional": true
+    },
+    "utf-8-validate": {
+      "optional": true
+    }
+  },
+  "devDependencies": {
+    "@eslint/js": "^10.0.1",
+    "benchmark": "^2.1.4",
+    "bufferutil": "^4.0.1",
+    "eslint": "^10.0.1",
+    "eslint-config-prettier": "^10.0.1",
+    "eslint-plugin-prettier": "^5.0.0",
+    "globals": "^17.0.0",
+    "mocha": "^8.4.0",
+    "nyc": "^15.0.0",
+    "prettier": "^3.0.0",
+    "utf-8-validate": "^6.0.0"
+  }
+}
Index: frontend/node_modules/webpack-dev-server/node_modules/ws/wrapper.mjs
===================================================================
--- frontend/node_modules/webpack-dev-server/node_modules/ws/wrapper.mjs	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/node_modules/ws/wrapper.mjs	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+import createWebSocketStream from './lib/stream.js';
+import extension from './lib/extension.js';
+import PerMessageDeflate from './lib/permessage-deflate.js';
+import Receiver from './lib/receiver.js';
+import Sender from './lib/sender.js';
+import subprotocol from './lib/subprotocol.js';
+import WebSocket from './lib/websocket.js';
+import WebSocketServer from './lib/websocket-server.js';
+
+export {
+  createWebSocketStream,
+  extension,
+  PerMessageDeflate,
+  Receiver,
+  Sender,
+  subprotocol,
+  WebSocket,
+  WebSocketServer
+};
+
+export default WebSocket;
Index: frontend/node_modules/webpack-dev-server/package.json
===================================================================
--- frontend/node_modules/webpack-dev-server/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,147 @@
+{
+  "name": "webpack-dev-server",
+  "version": "4.15.2",
+  "description": "Serves a webpack app. Updates the browser on changes.",
+  "bin": "bin/webpack-dev-server.js",
+  "main": "lib/Server.js",
+  "types": "types/lib/Server.d.ts",
+  "author": "Tobias Koppers @sokra",
+  "bugs": "https://github.com/webpack/webpack-dev-server/issues",
+  "homepage": "https://github.com/webpack/webpack-dev-server#readme",
+  "repository": "https://github.com/webpack/webpack-dev-server",
+  "license": "MIT",
+  "funding": {
+    "type": "opencollective",
+    "url": "https://opencollective.com/webpack"
+  },
+  "files": [
+    "bin",
+    "lib",
+    "client",
+    "types"
+  ],
+  "engines": {
+    "node": ">= 12.13.0"
+  },
+  "scripts": {
+    "fmt:check": "prettier \"{**/*,*}.{js,json,md,yml,css,ts}\" --list-different",
+    "lint:js": "eslint . --cache",
+    "lint:types": "tsc --pretty --noEmit",
+    "lint": "npm-run-all -p \"fmt:**\" \"lint:**\"",
+    "fmt": "npm run fmt:check -- --write",
+    "fix:js": "npm run lint:js -- --fix",
+    "fix": "npm-run-all fix:js fmt",
+    "commitlint": "commitlint --from=master",
+    "build:client": "rimraf ./client/* && babel client-src/ --out-dir client/ --ignore \"client-src/webpack.config.js\" --ignore \"client-src/modules\" && webpack --config client-src/webpack.config.js",
+    "build:types": "rimraf ./types/* && tsc --declaration --emitDeclarationOnly --outDir types && node ./scripts/extend-webpack-types.js && prettier \"types/**/*.ts\" --write && prettier \"types/**/*.ts\" --write",
+    "build": "npm-run-all -p \"build:**\"",
+    "test:only": "jest",
+    "test:coverage": "npm run test:only -- --coverage",
+    "test:watch": "npm run test:coverage --watch",
+    "test": "npm run test:coverage",
+    "pretest": "npm run lint",
+    "prepare": "husky install && npm run build",
+    "release": "standard-version"
+  },
+  "dependencies": {
+    "@types/bonjour": "^3.5.9",
+    "@types/connect-history-api-fallback": "^1.3.5",
+    "@types/express": "^4.17.13",
+    "@types/serve-index": "^1.9.1",
+    "@types/serve-static": "^1.13.10",
+    "@types/sockjs": "^0.3.33",
+    "@types/ws": "^8.5.5",
+    "ansi-html-community": "^0.0.8",
+    "bonjour-service": "^1.0.11",
+    "chokidar": "^3.5.3",
+    "colorette": "^2.0.10",
+    "compression": "^1.7.4",
+    "connect-history-api-fallback": "^2.0.0",
+    "default-gateway": "^6.0.3",
+    "express": "^4.17.3",
+    "graceful-fs": "^4.2.6",
+    "html-entities": "^2.3.2",
+    "http-proxy-middleware": "^2.0.3",
+    "ipaddr.js": "^2.0.1",
+    "launch-editor": "^2.6.0",
+    "open": "^8.0.9",
+    "p-retry": "^4.5.0",
+    "rimraf": "^3.0.2",
+    "schema-utils": "^4.0.0",
+    "selfsigned": "^2.1.1",
+    "serve-index": "^1.9.1",
+    "sockjs": "^0.3.24",
+    "spdy": "^4.0.2",
+    "webpack-dev-middleware": "^5.3.4",
+    "ws": "^8.13.0"
+  },
+  "devDependencies": {
+    "@babel/cli": "^7.17.3",
+    "@babel/core": "^7.20.2",
+    "@babel/eslint-parser": "^7.17.0",
+    "@babel/plugin-transform-object-assign": "^7.14.5",
+    "@babel/plugin-transform-runtime": "^7.17.0",
+    "@babel/preset-env": "^7.20.2",
+    "@babel/runtime": "^7.20.1",
+    "@commitlint/cli": "^16.2.3",
+    "@commitlint/config-conventional": "^16.2.1",
+    "@types/compression": "^1.7.2",
+    "@types/default-gateway": "^3.0.1",
+    "@types/node": "^18.11.9",
+    "@types/node-forge": "^1.3.1",
+    "@types/rimraf": "^3.0.2",
+    "@types/sockjs-client": "^1.5.1",
+    "@types/trusted-types": "^2.0.2",
+    "acorn": "^8.2.4",
+    "babel-jest": "^28.1.3",
+    "babel-loader": "^8.2.4",
+    "body-parser": "^1.19.2",
+    "core-js": "^3.21.1",
+    "css-loader": "^5.2.4",
+    "eslint": "^8.28.0",
+    "eslint-config-prettier": "^8.4.0",
+    "eslint-config-webpack": "^1.2.5",
+    "eslint-plugin-import": "^2.23.2",
+    "execa": "^5.1.1",
+    "file-loader": "^6.2.0",
+    "html-webpack-plugin": "^4.5.2",
+    "http-proxy": "^1.18.1",
+    "husky": "^7.0.0",
+    "jest": "^28.1.3",
+    "jest-environment-jsdom": "^28.1.3",
+    "klona": "^2.0.4",
+    "less": "^4.1.1",
+    "less-loader": "^7.3.0",
+    "lint-staged": "^12.3.4",
+    "marked": "^4.2.3",
+    "memfs": "^3.4.12",
+    "npm-run-all": "^4.1.5",
+    "prettier": "^2.8.0",
+    "puppeteer": "^13.4.1",
+    "require-from-string": "^2.0.2",
+    "rimraf": "^3.0.2",
+    "sockjs-client": "^1.6.1",
+    "standard-version": "^9.3.0",
+    "strip-ansi-v6": "npm:strip-ansi@^6.0.0",
+    "style-loader": "^2.0.0",
+    "supertest": "^6.1.3",
+    "tcp-port-used": "^1.0.2",
+    "typescript": "^4.9.3",
+    "url-loader": "^4.1.1",
+    "wait-for-expect": "^3.0.2",
+    "webpack": "^5.81.0",
+    "webpack-cli": "^4.7.2",
+    "webpack-merge": "^5.8.0"
+  },
+  "peerDependencies": {
+    "webpack": "^4.37.0 || ^5.0.0"
+  },
+  "peerDependenciesMeta": {
+    "webpack-cli": {
+      "optional": true
+    },
+    "webpack": {
+      "optional": true
+    }
+  }
+}
Index: frontend/node_modules/webpack-dev-server/types/bin/cli-flags.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/bin/cli-flags.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/bin/cli-flags.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,987 @@
+declare const _exports: {
+  "allowed-hosts": {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: string[];
+        }
+    )[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "allowed-hosts-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  bonjour: {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  client: {
+    configs: {
+      description: string;
+      negatedDescription: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+      values: boolean[];
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "client-logging": {
+    configs: {
+      type: string;
+      values: string[];
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-overlay": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-overlay-errors": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-overlay-trusted-types-policy-name": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "client-overlay-warnings": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-overlay-runtime-errors": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-progress": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-reconnect": {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-transport": {
+    configs: (
+      | {
+          type: string;
+          values: string[];
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-url": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-url-hostname": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-url-password": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-url-pathname": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-url-port": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "client-web-socket-url-protocol": {
+    configs: (
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: string[];
+        }
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }
+    )[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "client-web-socket-url-username": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  compress: {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "history-api-fallback": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  host: {
+    configs: (
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: string[];
+        }
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  hot: {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }
+      | {
+          type: string;
+          values: string[];
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  http2: {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  https: {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-ca": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-ca-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-cacert": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-cacert-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-cert": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-cert-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-crl": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-crl-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-key": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-key-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-passphrase": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-pfx": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "https-pfx-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "https-request-cert": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  ipc: {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+      | {
+          type: string;
+          values: boolean[];
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "live-reload": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "magic-html": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  open: {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "open-app": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "open-app-name": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "open-app-name-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "open-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "open-target": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "open-target-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  port: {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+      | {
+          type: string;
+          values: string[];
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "server-options-ca": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-ca-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-cacert": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-cacert-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-cert": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-cert-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-crl": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-crl-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-key": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-key-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-passphrase": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-pfx": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-pfx-reset": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-options-request-cert": {
+    configs: {
+      description: string;
+      negatedDescription: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  "server-type": {
+    configs: {
+      description: string;
+      multiple: boolean;
+      path: string;
+      type: string;
+      values: string[];
+    }[];
+    description: string;
+    multiple: boolean;
+    simpleType: string;
+  };
+  static: {
+    configs: (
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }
+      | {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "static-directory": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "static-public-path": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "static-public-path-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "static-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "static-serve-index": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "static-watch": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      negatedDescription: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "watch-files": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "watch-files-reset": {
+    configs: {
+      type: string;
+      multiple: boolean;
+      description: string;
+      path: string;
+    }[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "web-socket-server": {
+    configs: (
+      | {
+          description: string;
+          negatedDescription: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: boolean[];
+        }
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: string[];
+        }
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+  "web-socket-server-type": {
+    configs: (
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: string[];
+        }
+      | {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }
+    )[];
+    description: string;
+    simpleType: string;
+    multiple: boolean;
+  };
+};
+export = _exports;
Index: frontend/node_modules/webpack-dev-server/types/bin/process-arguments.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/bin/process-arguments.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/bin/process-arguments.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+export = processArguments;
+/**
+ * @param {Record<string, Argument>} args object of arguments
+ * @param {any} config configuration
+ * @param {Record<string, string | number | boolean | RegExp | (string | number | boolean | RegExp)[]>} values object with values
+ * @returns {Problem[] | null} problems or null for success
+ */
+declare function processArguments(
+  args: Record<string, Argument>,
+  config: any,
+  values: Record<
+    string,
+    string | number | boolean | RegExp | (string | number | boolean | RegExp)[]
+  >
+): Problem[] | null;
+declare namespace processArguments {
+  export { ProblemType, Problem, LocalProblem, ArgumentConfig, Argument };
+}
+type Argument = {
+  description: string;
+  simpleType: "string" | "number" | "boolean";
+  multiple: boolean;
+  configs: ArgumentConfig[];
+};
+type Problem = {
+  type: ProblemType;
+  path: string;
+  argument: string;
+  value?: any | undefined;
+  index?: number | undefined;
+  expected?: string | undefined;
+};
+type ProblemType =
+  | "unknown-argument"
+  | "unexpected-non-array-in-path"
+  | "unexpected-non-object-in-path"
+  | "multiple-values-unexpected"
+  | "invalid-value";
+type LocalProblem = {
+  type: ProblemType;
+  path: string;
+  expected?: string | undefined;
+};
+type ArgumentConfig = {
+  description: string;
+  path: string;
+  multiple: boolean;
+  type: "enum" | "string" | "path" | "number" | "boolean" | "RegExp" | "reset";
+  values?: any[] | undefined;
+};
Index: frontend/node_modules/webpack-dev-server/types/bin/webpack-dev-server.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/bin/webpack-dev-server.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/bin/webpack-dev-server.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,27 @@
+#!/usr/bin/env node
+export type CliOption = {
+  /**
+   * display name
+   */
+  name: string;
+  /**
+   * npm package name
+   */
+  package: string;
+  /**
+   * name of the executable file
+   */
+  binName: string;
+  /**
+   * currently installed?
+   */
+  installed: boolean;
+  /**
+   * homepage
+   */
+  url: string;
+  /**
+   * preprocessor
+   */
+  preprocess: Function;
+};
Index: frontend/node_modules/webpack-dev-server/types/lib/Server.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/lib/Server.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/lib/Server.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3853 @@
+/// <reference types="node" />
+export = Server;
+declare class Server {
+  static get cli(): {
+    readonly getArguments: () => {
+      "allowed-hosts": {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+              values: string[];
+            }
+        )[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "allowed-hosts-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          /** @typedef {import("express").NextFunction} NextFunction */
+          /** @typedef {import("express").RequestHandler} ExpressRequestHandler */
+          /** @typedef {import("express").ErrorRequestHandler} ExpressErrorRequestHandler */
+          /** @typedef {import("chokidar").WatchOptions} WatchOptions */
+          /** @typedef {import("chokidar").FSWatcher} FSWatcher */
+          /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
+          /** @typedef {import("bonjour-service").Bonjour} Bonjour */
+          /** @typedef {import("bonjour-service").Service} BonjourOptions */
+          /** @typedef {import("http-proxy-middleware").RequestHandler} RequestHandler */
+          /** @typedef {import("http-proxy-middleware").Options} HttpProxyMiddlewareOptions */
+          /** @typedef {import("http-proxy-middleware").Filter} HttpProxyMiddlewareOptionsFilter */
+          /** @typedef {import("serve-index").Options} ServeIndexOptions */
+          /** @typedef {import("serve-static").ServeStaticOptions} ServeStaticOptions */
+          /** @typedef {import("ipaddr.js").IPv4} IPv4 */
+          /** @typedef {import("ipaddr.js").IPv6} IPv6 */
+          /** @typedef {import("net").Socket} Socket */
+          /** @typedef {import("http").IncomingMessage} IncomingMessage */
+          /** @typedef {import("open").Options} OpenOptions */
+          /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
+          /**
+           * @template Request, Response
+           * @typedef {import("webpack-dev-middleware").Options<Request, Response>} DevMiddlewareOptions
+           */
+          /**
+           * @template Request, Response
+           * @typedef {import("webpack-dev-middleware").Context<Request, Response>} DevMiddlewareContext
+           */
+          /**
+           * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host
+           */
+          /**
+           * @typedef {number | string | "auto"} Port
+           */
+          /**
+           * @typedef {Object} WatchFiles
+           * @property {string | string[]} paths
+           * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
+           */
+          /**
+           * @typedef {Object} Static
+           * @property {string} [directory]
+           * @property {string | string[]} [publicPath]
+           * @property {boolean | ServeIndexOptions} [serveIndex]
+           * @property {ServeStaticOptions} [staticOptions]
+           * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
+           */
+          /**
+           * @typedef {Object} NormalizedStatic
+           * @property {string} directory
+           * @property {string[]} publicPath
+           * @property {false | ServeIndexOptions} serveIndex
+           * @property {ServeStaticOptions} staticOptions
+           * @property {false | WatchOptions} watch
+           */
+          /**
+           * @typedef {Object} ServerConfiguration
+           * @property {"http" | "https" | "spdy" | string} [type]
+           * @property {ServerOptions} [options]
+           */
+          /**
+           * @typedef {Object} WebSocketServerConfiguration
+           * @property {"sockjs" | "ws" | string | Function} [type]
+           * @property {Record<string, any>} [options]
+           */
+          /**
+           * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+           */
+          /**
+           * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+           */
+          /**
+           * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+           */
+          /**
+           * @callback ByPass
+           * @param {Request} req
+           * @param {Response} res
+           * @param {ProxyConfigArrayItem} proxyConfig
+           */
+          /**
+           * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+           */
+          /**
+           * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+           */
+          /**
+           * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+           */
+          /**
+           * @typedef {Object} OpenApp
+           * @property {string} [name]
+           * @property {string[]} [arguments]
+           */
+          /**
+           * @typedef {Object} Open
+           * @property {string | string[] | OpenApp} [app]
+           * @property {string | string[]} [target]
+           */
+          /**
+           * @typedef {Object} NormalizedOpen
+           * @property {string} target
+           * @property {import("open").Options} options
+           */
+          /**
+           * @typedef {Object} WebSocketURL
+           * @property {string} [hostname]
+           * @property {string} [password]
+           * @property {string} [pathname]
+           * @property {number | string} [port]
+           * @property {string} [protocol]
+           * @property {string} [username]
+           */
+          /**
+           * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+           */
+          /**
+           * @typedef {Object} ClientConfiguration
+           * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+           * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+           * @property {boolean} [progress]
+           * @property {boolean | number} [reconnect]
+           * @property {"ws" | "sockjs" | string} [webSocketTransport]
+           * @property {string | WebSocketURL} [webSocketURL]
+           */
+          /**
+           * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+           */
+          /**
+           * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+           */
+          /**
+           * @typedef {Object} Configuration
+           * @property {boolean | string} [ipc]
+           * @property {Host} [host]
+           * @property {Port} [port]
+           * @property {boolean | "only"} [hot]
+           * @property {boolean} [liveReload]
+           * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+           * @property {boolean} [compress]
+           * @property {boolean} [magicHtml]
+           * @property {"auto" | "all" | string | string[]} [allowedHosts]
+           * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+           * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+           * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+           * @property {boolean | string | Static | Array<string | Static>} [static]
+           * @property {boolean | ServerOptions} [https]
+           * @property {boolean} [http2]
+           * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+           * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+           * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+           * @property {boolean | string | Open | Array<string | Open>} [open]
+           * @property {boolean} [setupExitSignals]
+           * @property {boolean | ClientConfiguration} [client]
+           * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+           * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+           * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+           * @property {(devServer: Server) => void} [onListening]
+           * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+           */
+          description: string;
+          path: string;
+        }[];
+        /** @typedef {import("chokidar").FSWatcher} FSWatcher */
+        /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */
+        /** @typedef {import("bonjour-service").Bonjour} Bonjour */
+        /** @typedef {import("bonjour-service").Service} BonjourOptions */
+        /** @typedef {import("http-proxy-middleware").RequestHandler} RequestHandler */
+        /** @typedef {import("http-proxy-middleware").Options} HttpProxyMiddlewareOptions */
+        /** @typedef {import("http-proxy-middleware").Filter} HttpProxyMiddlewareOptionsFilter */
+        /** @typedef {import("serve-index").Options} ServeIndexOptions */
+        /** @typedef {import("serve-static").ServeStaticOptions} ServeStaticOptions */
+        /** @typedef {import("ipaddr.js").IPv4} IPv4 */
+        /** @typedef {import("ipaddr.js").IPv6} IPv6 */
+        /** @typedef {import("net").Socket} Socket */
+        /** @typedef {import("http").IncomingMessage} IncomingMessage */
+        /** @typedef {import("open").Options} OpenOptions */
+        /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
+        /**
+         * @template Request, Response
+         * @typedef {import("webpack-dev-middleware").Options<Request, Response>} DevMiddlewareOptions
+         */
+        /**
+         * @template Request, Response
+         * @typedef {import("webpack-dev-middleware").Context<Request, Response>} DevMiddlewareContext
+         */
+        /**
+         * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host
+         */
+        /**
+         * @typedef {number | string | "auto"} Port
+         */
+        /**
+         * @typedef {Object} WatchFiles
+         * @property {string | string[]} paths
+         * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
+         */
+        /**
+         * @typedef {Object} Static
+         * @property {string} [directory]
+         * @property {string | string[]} [publicPath]
+         * @property {boolean | ServeIndexOptions} [serveIndex]
+         * @property {ServeStaticOptions} [staticOptions]
+         * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
+         */
+        /**
+         * @typedef {Object} NormalizedStatic
+         * @property {string} directory
+         * @property {string[]} publicPath
+         * @property {false | ServeIndexOptions} serveIndex
+         * @property {ServeStaticOptions} staticOptions
+         * @property {false | WatchOptions} watch
+         */
+        /**
+         * @typedef {Object} ServerConfiguration
+         * @property {"http" | "https" | "spdy" | string} [type]
+         * @property {ServerOptions} [options]
+         */
+        /**
+         * @typedef {Object} WebSocketServerConfiguration
+         * @property {"sockjs" | "ws" | string | Function} [type]
+         * @property {Record<string, any>} [options]
+         */
+        /**
+         * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+         */
+        /**
+         * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+         */
+        /**
+         * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+         */
+        /**
+         * @callback ByPass
+         * @param {Request} req
+         * @param {Response} res
+         * @param {ProxyConfigArrayItem} proxyConfig
+         */
+        /**
+         * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+         */
+        /**
+         * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+         */
+        /**
+         * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+         */
+        /**
+         * @typedef {Object} OpenApp
+         * @property {string} [name]
+         * @property {string[]} [arguments]
+         */
+        /**
+         * @typedef {Object} Open
+         * @property {string | string[] | OpenApp} [app]
+         * @property {string | string[]} [target]
+         */
+        /**
+         * @typedef {Object} NormalizedOpen
+         * @property {string} target
+         * @property {import("open").Options} options
+         */
+        /**
+         * @typedef {Object} WebSocketURL
+         * @property {string} [hostname]
+         * @property {string} [password]
+         * @property {string} [pathname]
+         * @property {number | string} [port]
+         * @property {string} [protocol]
+         * @property {string} [username]
+         */
+        /**
+         * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+         */
+        /**
+         * @typedef {Object} ClientConfiguration
+         * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+         * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+         * @property {boolean} [progress]
+         * @property {boolean | number} [reconnect]
+         * @property {"ws" | "sockjs" | string} [webSocketTransport]
+         * @property {string | WebSocketURL} [webSocketURL]
+         */
+        /**
+         * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+         */
+        /**
+         * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+         */
+        /**
+         * @typedef {Object} Configuration
+         * @property {boolean | string} [ipc]
+         * @property {Host} [host]
+         * @property {Port} [port]
+         * @property {boolean | "only"} [hot]
+         * @property {boolean} [liveReload]
+         * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+         * @property {boolean} [compress]
+         * @property {boolean} [magicHtml]
+         * @property {"auto" | "all" | string | string[]} [allowedHosts]
+         * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+         * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+         * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+         * @property {boolean | string | Static | Array<string | Static>} [static]
+         * @property {boolean | ServerOptions} [https]
+         * @property {boolean} [http2]
+         * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+         * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+         * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+         * @property {boolean | string | Open | Array<string | Open>} [open]
+         * @property {boolean} [setupExitSignals]
+         * @property {boolean | ClientConfiguration} [client]
+         * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+         * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+         * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+         * @property {(devServer: Server) => void} [onListening]
+         * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+         */
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      bonjour: {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      client: {
+        configs: {
+          description: string;
+          negatedDescription: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: boolean[];
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "client-logging": {
+        configs: {
+          type: string;
+          values: string[];
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-overlay": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-overlay-errors": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          /**
+           * @typedef {Object} ServerConfiguration
+           * @property {"http" | "https" | "spdy" | string} [type]
+           * @property {ServerOptions} [options]
+           */
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        /**
+         * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+         */
+        /**
+         * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+         */
+        /**
+         * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+         */
+        /**
+         * @callback ByPass
+         * @param {Request} req
+         * @param {Response} res
+         * @param {ProxyConfigArrayItem} proxyConfig
+         */
+        /**
+         * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+         */
+        /**
+         * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+         */
+        /**
+         * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+         */
+        /**
+         * @typedef {Object} OpenApp
+         * @property {string} [name]
+         * @property {string[]} [arguments]
+         */
+        /**
+         * @typedef {Object} Open
+         * @property {string | string[] | OpenApp} [app]
+         * @property {string | string[]} [target]
+         */
+        /**
+         * @typedef {Object} NormalizedOpen
+         * @property {string} target
+         * @property {import("open").Options} options
+         */
+        /**
+         * @typedef {Object} WebSocketURL
+         * @property {string} [hostname]
+         * @property {string} [password]
+         * @property {string} [pathname]
+         * @property {number | string} [port]
+         * @property {string} [protocol]
+         * @property {string} [username]
+         */
+        /**
+         * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+         */
+        /**
+         * @typedef {Object} ClientConfiguration
+         * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+         * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+         * @property {boolean} [progress]
+         * @property {boolean | number} [reconnect]
+         * @property {"ws" | "sockjs" | string} [webSocketTransport]
+         * @property {string | WebSocketURL} [webSocketURL]
+         */
+        /**
+         * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+         */
+        /**
+         * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+         */
+        /**
+         * @typedef {Object} Configuration
+         * @property {boolean | string} [ipc]
+         * @property {Host} [host]
+         * @property {Port} [port]
+         * @property {boolean | "only"} [hot]
+         * @property {boolean} [liveReload]
+         * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+         * @property {boolean} [compress]
+         * @property {boolean} [magicHtml]
+         * @property {"auto" | "all" | string | string[]} [allowedHosts]
+         * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+         * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+         * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+         * @property {boolean | string | Static | Array<string | Static>} [static]
+         * @property {boolean | ServerOptions} [https]
+         * @property {boolean} [http2]
+         * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+         * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+         * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+         * @property {boolean | string | Open | Array<string | Open>} [open]
+         * @property {boolean} [setupExitSignals]
+         * @property {boolean | ClientConfiguration} [client]
+         * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+         * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+         * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+         * @property {(devServer: Server) => void} [onListening]
+         * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+         */
+        multiple: boolean;
+      };
+      "client-overlay-trusted-types-policy-name": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          /**
+           * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+           */
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "client-overlay-warnings": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-overlay-runtime-errors": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-progress": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-reconnect": {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              negatedDescription: string;
+              path: string;
+            }
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-web-socket-transport": {
+        configs: (
+          | {
+              type: string;
+              values: string[];
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-web-socket-url": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-web-socket-url-hostname": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        /** @type {T} */ multiple: boolean;
+      };
+      "client-web-socket-url-password": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-web-socket-url-pathname": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-web-socket-url-port": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "client-web-socket-url-protocol": {
+        configs: (
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+              values: string[];
+            }
+          | {
+              description: string;
+              /**
+               * @private
+               * @type {RequestHandler[]}
+               */
+              multiple: boolean;
+              path: string;
+              type: string;
+              /**
+               * @type {Socket[]}
+               */
+            }
+        )[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "client-web-socket-url-username": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      compress: {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "history-api-fallback": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      host: {
+        configs: (
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+              values: string[];
+            }
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      hot: {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              negatedDescription: string;
+              path: string;
+            }
+          | {
+              type: string;
+              values: string[];
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      http2: {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      https: {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      /**
+       * @type {string | undefined}
+       */
+      "https-ca": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "https-ca-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "https-cacert": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "https-cacert-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "https-cert": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          /** @type {ClientConfiguration} */ description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "https-cert-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "https-crl": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "https-crl-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "https-key": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "https-key-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        /** @type {string} */ simpleType: string;
+      };
+      "https-passphrase": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "https-pfx": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "https-pfx-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "https-request-cert": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      ipc: {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+          | {
+              type: string;
+              values: boolean[];
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "live-reload": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        /**
+         * prependEntry Method for webpack 4
+         * @param {any} originalEntry
+         * @param {any} newAdditionalEntries
+         * @returns {any}
+         */
+        multiple: boolean;
+      };
+      "magic-html": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      open: {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+          | {
+              /** @type {any} */
+              type: string;
+              multiple: boolean;
+              /** @type {any} */ description: string;
+              negatedDescription: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "open-app": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "open-app-name": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "open-app-name-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "open-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "open-target": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "open-target-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      port: {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+          | {
+              type: string;
+              values: string[];
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "server-options-ca": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-ca-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-cacert": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-cacert-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-cert": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-cert-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-crl": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-crl-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-key": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-key-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-passphrase": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-pfx": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-pfx-reset": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-options-request-cert": {
+        configs: {
+          description: string;
+          negatedDescription: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      "server-type": {
+        configs: {
+          description: string;
+          multiple: boolean;
+          path: string;
+          type: string;
+          values: string[];
+        }[];
+        description: string;
+        multiple: boolean;
+        simpleType: string;
+      };
+      static: {
+        configs: (
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              path: string;
+            }
+          | {
+              type: string;
+              multiple: boolean;
+              description: string;
+              negatedDescription: string;
+              path: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "static-directory": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "static-public-path": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "static-public-path-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "static-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean /** @type {any} */;
+      };
+      /** @type {any} */
+      "static-serve-index": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "static-watch": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          negatedDescription: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "watch-files": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "watch-files-reset": {
+        configs: {
+          type: string;
+          multiple: boolean;
+          description: string;
+          path: string;
+        }[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "web-socket-server": {
+        configs: (
+          | {
+              description: string;
+              negatedDescription: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+              values: boolean[];
+            }
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+              values: string[];
+            }
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+      "web-socket-server-type": {
+        configs: (
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+              values: string[];
+            }
+          | {
+              description: string;
+              multiple: boolean;
+              path: string;
+              type: string;
+            }
+        )[];
+        description: string;
+        simpleType: string;
+        multiple: boolean;
+      };
+    };
+    readonly processArguments: (
+      args: Record<string, import("../bin/process-arguments").Argument>,
+      config: any,
+      values: Record<
+        string,
+        | string
+        | number
+        | boolean
+        | RegExp
+        | (string | number | boolean | RegExp)[]
+      >
+    ) => import("../bin/process-arguments").Problem[] | null;
+  };
+  static get schema(): {
+    title: string;
+    type: string;
+    definitions: {
+      AllowedHosts: {
+        anyOf: (
+          | {
+              type: string;
+              minItems: number;
+              items: {
+                $ref: string;
+              };
+              enum?: undefined;
+              $ref?: undefined;
+            }
+          | {
+              enum: string[];
+              type?: undefined;
+              minItems?: undefined;
+              items?: undefined;
+              $ref?: undefined;
+            }
+          | {
+              $ref: string;
+              type?: undefined;
+              minItems?: undefined;
+              items?: undefined;
+              enum?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      AllowedHostsItem: {
+        type: string;
+        minLength: number;
+      };
+      Bonjour: {
+        anyOf: (
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              description?: undefined;
+              link?: undefined;
+            }
+          | {
+              type: string;
+              description: string;
+              link: string;
+              cli?: undefined;
+            }
+        )[];
+        description: string;
+        link: string /** @typedef {import("connect-history-api-fallback").Options} ConnectHistoryApiFallbackOptions */;
+      };
+      Client: {
+        description: string;
+        link: string;
+        anyOf: (
+          | {
+              enum: boolean[];
+              cli: {
+                negatedDescription: string;
+              };
+              type?: undefined;
+              additionalProperties?: undefined;
+              properties?: undefined;
+            }
+          | {
+              type: string;
+              additionalProperties: boolean;
+              properties: {
+                logging: {
+                  $ref: string;
+                };
+                overlay: {
+                  $ref: string;
+                };
+                progress: {
+                  $ref: string;
+                };
+                reconnect: {
+                  $ref: string;
+                };
+                webSocketTransport: {
+                  /** @typedef {import("https").ServerOptions & { spdy?: { plain?: boolean | undefined, ssl?: boolean | undefined, 'x-forwarded-for'?: string | undefined, protocol?: string | undefined, protocols?: string[] | undefined }}} ServerOptions */
+                  /**
+                   * @template Request, Response
+                   * @typedef {import("webpack-dev-middleware").Options<Request, Response>} DevMiddlewareOptions
+                   */
+                  /**
+                   * @template Request, Response
+                   * @typedef {import("webpack-dev-middleware").Context<Request, Response>} DevMiddlewareContext
+                   */
+                  /**
+                   * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host
+                   */
+                  /**
+                   * @typedef {number | string | "auto"} Port
+                   */
+                  /**
+                   * @typedef {Object} WatchFiles
+                   * @property {string | string[]} paths
+                   * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
+                   */
+                  /**
+                   * @typedef {Object} Static
+                   * @property {string} [directory]
+                   * @property {string | string[]} [publicPath]
+                   * @property {boolean | ServeIndexOptions} [serveIndex]
+                   * @property {ServeStaticOptions} [staticOptions]
+                   * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
+                   */
+                  /**
+                   * @typedef {Object} NormalizedStatic
+                   * @property {string} directory
+                   * @property {string[]} publicPath
+                   * @property {false | ServeIndexOptions} serveIndex
+                   * @property {ServeStaticOptions} staticOptions
+                   * @property {false | WatchOptions} watch
+                   */
+                  /**
+                   * @typedef {Object} ServerConfiguration
+                   * @property {"http" | "https" | "spdy" | string} [type]
+                   * @property {ServerOptions} [options]
+                   */
+                  /**
+                   * @typedef {Object} WebSocketServerConfiguration
+                   * @property {"sockjs" | "ws" | string | Function} [type]
+                   * @property {Record<string, any>} [options]
+                   */
+                  /**
+                   * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+                   */
+                  /**
+                   * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+                   */
+                  /**
+                   * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+                   */
+                  /**
+                   * @callback ByPass
+                   * @param {Request} req
+                   * @param {Response} res
+                   * @param {ProxyConfigArrayItem} proxyConfig
+                   */
+                  /**
+                   * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+                   */
+                  /**
+                   * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+                   */
+                  /**
+                   * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+                   */
+                  /**
+                   * @typedef {Object} OpenApp
+                   * @property {string} [name]
+                   * @property {string[]} [arguments]
+                   */
+                  /**
+                   * @typedef {Object} Open
+                   * @property {string | string[] | OpenApp} [app]
+                   * @property {string | string[]} [target]
+                   */
+                  /**
+                   * @typedef {Object} NormalizedOpen
+                   * @property {string} target
+                   * @property {import("open").Options} options
+                   */
+                  /**
+                   * @typedef {Object} WebSocketURL
+                   * @property {string} [hostname]
+                   * @property {string} [password]
+                   * @property {string} [pathname]
+                   * @property {number | string} [port]
+                   * @property {string} [protocol]
+                   * @property {string} [username]
+                   */
+                  /**
+                   * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+                   */
+                  /**
+                   * @typedef {Object} ClientConfiguration
+                   * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+                   * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+                   * @property {boolean} [progress]
+                   * @property {boolean | number} [reconnect]
+                   * @property {"ws" | "sockjs" | string} [webSocketTransport]
+                   * @property {string | WebSocketURL} [webSocketURL]
+                   */
+                  /**
+                   * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+                   */
+                  /**
+                   * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+                   */
+                  /**
+                   * @typedef {Object} Configuration
+                   * @property {boolean | string} [ipc]
+                   * @property {Host} [host]
+                   * @property {Port} [port]
+                   * @property {boolean | "only"} [hot]
+                   * @property {boolean} [liveReload]
+                   * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+                   * @property {boolean} [compress]
+                   * @property {boolean} [magicHtml]
+                   * @property {"auto" | "all" | string | string[]} [allowedHosts]
+                   * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+                   * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+                   * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+                   * @property {boolean | string | Static | Array<string | Static>} [static]
+                   * @property {boolean | ServerOptions} [https]
+                   * @property {boolean} [http2]
+                   * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+                   * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+                   * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+                   * @property {boolean | string | Open | Array<string | Open>} [open]
+                   * @property {boolean} [setupExitSignals]
+                   * @property {boolean | ClientConfiguration} [client]
+                   * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+                   * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+                   * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+                   * @property {(devServer: Server) => void} [onListening]
+                   * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+                   */
+                  $ref: string;
+                };
+                webSocketURL: {
+                  $ref: string;
+                };
+              };
+              enum?: undefined;
+              cli?: undefined;
+            }
+        )[];
+      };
+      ClientLogging: {
+        /**
+         * @template Request, Response
+         * @typedef {import("webpack-dev-middleware").Options<Request, Response>} DevMiddlewareOptions
+         */
+        /**
+         * @template Request, Response
+         * @typedef {import("webpack-dev-middleware").Context<Request, Response>} DevMiddlewareContext
+         */
+        /**
+         * @typedef {"local-ip" | "local-ipv4" | "local-ipv6" | string} Host
+         */
+        /**
+         * @typedef {number | string | "auto"} Port
+         */
+        /**
+         * @typedef {Object} WatchFiles
+         * @property {string | string[]} paths
+         * @property {WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [options]
+         */
+        /**
+         * @typedef {Object} Static
+         * @property {string} [directory]
+         * @property {string | string[]} [publicPath]
+         * @property {boolean | ServeIndexOptions} [serveIndex]
+         * @property {ServeStaticOptions} [staticOptions]
+         * @property {boolean | WatchOptions & { aggregateTimeout?: number, ignored?: WatchOptions["ignored"], poll?: number | boolean }} [watch]
+         */
+        /**
+         * @typedef {Object} NormalizedStatic
+         * @property {string} directory
+         * @property {string[]} publicPath
+         * @property {false | ServeIndexOptions} serveIndex
+         * @property {ServeStaticOptions} staticOptions
+         * @property {false | WatchOptions} watch
+         */
+        /**
+         * @typedef {Object} ServerConfiguration
+         * @property {"http" | "https" | "spdy" | string} [type]
+         * @property {ServerOptions} [options]
+         */
+        /**
+         * @typedef {Object} WebSocketServerConfiguration
+         * @property {"sockjs" | "ws" | string | Function} [type]
+         * @property {Record<string, any>} [options]
+         */
+        /**
+         * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+         */
+        /**
+         * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+         */
+        /**
+         * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+         */
+        /**
+         * @callback ByPass
+         * @param {Request} req
+         * @param {Response} res
+         * @param {ProxyConfigArrayItem} proxyConfig
+         */
+        /**
+         * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+         */
+        /**
+         * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+         */
+        /**
+         * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+         */
+        /**
+         * @typedef {Object} OpenApp
+         * @property {string} [name]
+         * @property {string[]} [arguments]
+         */
+        /**
+         * @typedef {Object} Open
+         * @property {string | string[] | OpenApp} [app]
+         * @property {string | string[]} [target]
+         */
+        /**
+         * @typedef {Object} NormalizedOpen
+         * @property {string} target
+         * @property {import("open").Options} options
+         */
+        /**
+         * @typedef {Object} WebSocketURL
+         * @property {string} [hostname]
+         * @property {string} [password]
+         * @property {string} [pathname]
+         * @property {number | string} [port]
+         * @property {string} [protocol]
+         * @property {string} [username]
+         */
+        /**
+         * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+         */
+        /**
+         * @typedef {Object} ClientConfiguration
+         * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+         * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+         * @property {boolean} [progress]
+         * @property {boolean | number} [reconnect]
+         * @property {"ws" | "sockjs" | string} [webSocketTransport]
+         * @property {string | WebSocketURL} [webSocketURL]
+         */
+        /**
+         * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+         */
+        /**
+         * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+         */
+        /**
+         * @typedef {Object} Configuration
+         * @property {boolean | string} [ipc]
+         * @property {Host} [host]
+         * @property {Port} [port]
+         * @property {boolean | "only"} [hot]
+         * @property {boolean} [liveReload]
+         * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+         * @property {boolean} [compress]
+         * @property {boolean} [magicHtml]
+         * @property {"auto" | "all" | string | string[]} [allowedHosts]
+         * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+         * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+         * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+         * @property {boolean | string | Static | Array<string | Static>} [static]
+         * @property {boolean | ServerOptions} [https]
+         * @property {boolean} [http2]
+         * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+         * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+         * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+         * @property {boolean | string | Open | Array<string | Open>} [open]
+         * @property {boolean} [setupExitSignals]
+         * @property {boolean | ClientConfiguration} [client]
+         * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+         * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+         * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+         * @property {(devServer: Server) => void} [onListening]
+         * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+         */
+        enum: string[];
+        description: string;
+        link: string;
+      };
+      ClientOverlay: {
+        anyOf: (
+          | {
+              description: string;
+              link: string;
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              additionalProperties?: undefined;
+              properties?: undefined;
+            }
+          | {
+              type: string;
+              additionalProperties: boolean;
+              properties: {
+                errors: {
+                  anyOf: (
+                    | {
+                        description: string;
+                        type: string;
+                        cli: {
+                          negatedDescription: string;
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        /**
+                         * @typedef {Object} WebSocketServerConfiguration
+                         * @property {"sockjs" | "ws" | string | Function} [type]
+                         * @property {Record<string, any>} [options]
+                         */
+                        /**
+                         * @typedef {(import("ws").WebSocket | import("sockjs").Connection & { send: import("ws").WebSocket["send"], terminate: import("ws").WebSocket["terminate"], ping: import("ws").WebSocket["ping"] }) & { isAlive?: boolean }} ClientConnection
+                         */
+                        /**
+                         * @typedef {import("ws").WebSocketServer | import("sockjs").Server & { close: import("ws").WebSocketServer["close"] }} WebSocketServer
+                         */
+                        /**
+                         * @typedef {{ implementation: WebSocketServer, clients: ClientConnection[] }} WebSocketServerImplementation
+                         */
+                        /**
+                         * @callback ByPass
+                         * @param {Request} req
+                         * @param {Response} res
+                         * @param {ProxyConfigArrayItem} proxyConfig
+                         */
+                        /**
+                         * @typedef {{ path?: HttpProxyMiddlewareOptionsFilter | undefined, context?: HttpProxyMiddlewareOptionsFilter | undefined } & { bypass?: ByPass } & HttpProxyMiddlewareOptions } ProxyConfigArrayItem
+                         */
+                        /**
+                         * @typedef {(ProxyConfigArrayItem | ((req?: Request | undefined, res?: Response | undefined, next?: NextFunction | undefined) => ProxyConfigArrayItem))[]} ProxyConfigArray
+                         */
+                        /**
+                         * @typedef {{ [url: string]: string | ProxyConfigArrayItem }} ProxyConfigMap
+                         */
+                        /**
+                         * @typedef {Object} OpenApp
+                         * @property {string} [name]
+                         * @property {string[]} [arguments]
+                         */
+                        /**
+                         * @typedef {Object} Open
+                         * @property {string | string[] | OpenApp} [app]
+                         * @property {string | string[]} [target]
+                         */
+                        /**
+                         * @typedef {Object} NormalizedOpen
+                         * @property {string} target
+                         * @property {import("open").Options} options
+                         */
+                        /**
+                         * @typedef {Object} WebSocketURL
+                         * @property {string} [hostname]
+                         * @property {string} [password]
+                         * @property {string} [pathname]
+                         * @property {number | string} [port]
+                         * @property {string} [protocol]
+                         * @property {string} [username]
+                         */
+                        /**
+                         * @typedef {boolean | ((error: Error) => void)} OverlayMessageOptions
+                         */
+                        /**
+                         * @typedef {Object} ClientConfiguration
+                         * @property {"log" | "info" | "warn" | "error" | "none" | "verbose"} [logging]
+                         * @property {boolean  | { warnings?: OverlayMessageOptions, errors?: OverlayMessageOptions, runtimeErrors?: OverlayMessageOptions }} [overlay]
+                         * @property {boolean} [progress]
+                         * @property {boolean | number} [reconnect]
+                         * @property {"ws" | "sockjs" | string} [webSocketTransport]
+                         * @property {string | WebSocketURL} [webSocketURL]
+                         */
+                        /**
+                         * @typedef {Array<{ key: string; value: string }> | Record<string, string | string[]>} Headers
+                         */
+                        /**
+                         * @typedef {{ name?: string, path?: string, middleware: ExpressRequestHandler | ExpressErrorRequestHandler } | ExpressRequestHandler | ExpressErrorRequestHandler} Middleware
+                         */
+                        /**
+                         * @typedef {Object} Configuration
+                         * @property {boolean | string} [ipc]
+                         * @property {Host} [host]
+                         * @property {Port} [port]
+                         * @property {boolean | "only"} [hot]
+                         * @property {boolean} [liveReload]
+                         * @property {DevMiddlewareOptions<Request, Response>} [devMiddleware]
+                         * @property {boolean} [compress]
+                         * @property {boolean} [magicHtml]
+                         * @property {"auto" | "all" | string | string[]} [allowedHosts]
+                         * @property {boolean | ConnectHistoryApiFallbackOptions} [historyApiFallback]
+                         * @property {boolean | Record<string, never> | BonjourOptions} [bonjour]
+                         * @property {string | string[] | WatchFiles | Array<string | WatchFiles>} [watchFiles]
+                         * @property {boolean | string | Static | Array<string | Static>} [static]
+                         * @property {boolean | ServerOptions} [https]
+                         * @property {boolean} [http2]
+                         * @property {"http" | "https" | "spdy" | string | ServerConfiguration} [server]
+                         * @property {boolean | "sockjs" | "ws" | string | WebSocketServerConfiguration} [webSocketServer]
+                         * @property {ProxyConfigMap | ProxyConfigArrayItem | ProxyConfigArray} [proxy]
+                         * @property {boolean | string | Open | Array<string | Open>} [open]
+                         * @property {boolean} [setupExitSignals]
+                         * @property {boolean | ClientConfiguration} [client]
+                         * @property {Headers | ((req: Request, res: Response, context: DevMiddlewareContext<Request, Response>) => Headers)} [headers]
+                         * @property {(devServer: Server) => void} [onAfterSetupMiddleware]
+                         * @property {(devServer: Server) => void} [onBeforeSetupMiddleware]
+                         * @property {(devServer: Server) => void} [onListening]
+                         * @property {(middlewares: Middleware[], devServer: Server) => Middleware[]} [setupMiddlewares]
+                         */
+                        description: string;
+                        type?: undefined;
+                        cli?: undefined;
+                      }
+                  )[];
+                };
+                warnings: {
+                  anyOf: (
+                    | {
+                        description: string;
+                        type: string;
+                        cli: {
+                          negatedDescription: string;
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        description: string;
+                        type?: undefined;
+                        cli?: undefined;
+                      }
+                  )[];
+                };
+                runtimeErrors: {
+                  anyOf: (
+                    | {
+                        description: string;
+                        type: string;
+                        cli: {
+                          negatedDescription: string;
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        description: string;
+                        type?: undefined;
+                        cli?: undefined;
+                      }
+                  )[];
+                };
+                trustedTypesPolicyName: {
+                  description: string;
+                  type: string;
+                };
+              };
+              description?: undefined;
+              link?: undefined;
+              cli?: undefined;
+            }
+        )[];
+      };
+      ClientProgress: {
+        description: string;
+        link: string;
+        type: string;
+        cli: {
+          negatedDescription: string;
+        };
+      };
+      ClientReconnect: {
+        description: string;
+        link: string;
+        anyOf: (
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              minimum?: undefined;
+            }
+          | {
+              type: string;
+              minimum: number;
+              cli?: undefined;
+            }
+        )[];
+      };
+      ClientWebSocketTransport: {
+        anyOf: {
+          $ref: string;
+        }[];
+        description: string;
+        link: string;
+      };
+      ClientWebSocketTransportEnum: {
+        enum: string[];
+      };
+      ClientWebSocketTransportString: {
+        type: string;
+        minLength: number;
+      };
+      ClientWebSocketURL: {
+        description: string;
+        link: string;
+        anyOf: (
+          | {
+              type: string;
+              minLength: number;
+              additionalProperties?: undefined;
+              properties?: undefined;
+            }
+          | {
+              type: string;
+              additionalProperties: boolean;
+              properties: {
+                hostname: {
+                  description: string;
+                  type: string;
+                  minLength: number;
+                };
+                pathname: {
+                  description: string;
+                  type: string;
+                };
+                password: {
+                  description: string;
+                  type: string;
+                };
+                port: {
+                  description: string;
+                  anyOf: (
+                    | {
+                        type: string;
+                        minLength?: undefined;
+                      }
+                    | {
+                        type: string;
+                        minLength: number;
+                      }
+                  )[];
+                };
+                protocol: {
+                  description: string;
+                  anyOf: (
+                    | {
+                        enum: string[];
+                        type?: undefined;
+                        minLength?: undefined;
+                      }
+                    | {
+                        type: string;
+                        minLength: number;
+                        enum?: undefined;
+                      }
+                  )[];
+                };
+                username: {
+                  description: string;
+                  type: string;
+                };
+              };
+              minLength?: undefined;
+            }
+        )[];
+      };
+      Compress: {
+        type: string;
+        description: string;
+        link: string;
+        cli: {
+          negatedDescription: string;
+        };
+      };
+      DevMiddleware: {
+        description: string;
+        link: string;
+        type: string;
+        additionalProperties: boolean;
+      };
+      HTTP2: {
+        type: string;
+        description: string;
+        link: string;
+        cli: {
+          negatedDescription: string;
+        };
+      };
+      HTTPS: {
+        anyOf: (
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              additionalProperties?: undefined;
+              properties?: undefined;
+            }
+          | {
+              type: string;
+              additionalProperties: boolean;
+              properties: {
+                passphrase: {
+                  type: string;
+                  description: string;
+                };
+                requestCert: {
+                  type: string;
+                  description: string;
+                  cli: {
+                    negatedDescription: string;
+                  };
+                };
+                /**
+                 * @private
+                 * @type {string | undefined}
+                 */
+                ca: {
+                  anyOf: (
+                    | {
+                        type: string;
+                        items: {
+                          anyOf: (
+                            | {
+                                type: string;
+                                instanceof?: undefined;
+                              }
+                            | {
+                                instanceof: string;
+                                type?: undefined;
+                              }
+                          )[];
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        type: string;
+                        items?: undefined;
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        type?: undefined;
+                        items?: undefined;
+                      }
+                  )[];
+                  description: string;
+                };
+                cacert: {
+                  anyOf: (
+                    | {
+                        type: string;
+                        items: {
+                          anyOf: (
+                            | {
+                                type: string;
+                                instanceof?: undefined;
+                              }
+                            | {
+                                instanceof: string;
+                                type?: undefined;
+                              }
+                          )[];
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        type: string;
+                        items?: undefined;
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        type?: undefined;
+                        items?: undefined;
+                      }
+                  )[];
+                  description: string;
+                };
+                cert: {
+                  anyOf: (
+                    | {
+                        type: string;
+                        items: {
+                          anyOf: (
+                            | {
+                                type: string;
+                                instanceof?: undefined;
+                              }
+                            | {
+                                instanceof: string;
+                                type?: undefined;
+                              }
+                          )[];
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        type: string;
+                        items?: undefined;
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        type?: undefined;
+                        items?: undefined;
+                      }
+                  )[];
+                  description: string;
+                };
+                crl: {
+                  anyOf: (
+                    | {
+                        type: string;
+                        items: {
+                          anyOf: (
+                            | {
+                                type: string;
+                                instanceof?: undefined;
+                              }
+                            | {
+                                instanceof: string;
+                                type?: undefined;
+                              }
+                          )[];
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        type: string;
+                        items?: undefined;
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        type?: undefined;
+                        items?: undefined;
+                      }
+                  )[];
+                  description: string;
+                };
+                key: {
+                  anyOf: (
+                    | {
+                        type: string;
+                        items: {
+                          anyOf: (
+                            | {
+                                type: string;
+                                instanceof?: undefined;
+                                additionalProperties?: undefined;
+                              }
+                            | {
+                                instanceof: string;
+                                type?: undefined;
+                                additionalProperties?: undefined;
+                              }
+                            | {
+                                type: string;
+                                additionalProperties: boolean;
+                                instanceof?: undefined;
+                              }
+                          )[];
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        type: string;
+                        items?: undefined;
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        type?: undefined;
+                        items?: undefined;
+                      }
+                  )[];
+                  description: string;
+                };
+                pfx: {
+                  anyOf: (
+                    | {
+                        type: string;
+                        items: {
+                          anyOf: (
+                            | {
+                                type: string;
+                                instanceof?: undefined;
+                                additionalProperties?: undefined;
+                              }
+                            | {
+                                instanceof: string;
+                                type?: undefined;
+                                additionalProperties?: undefined;
+                              }
+                            | {
+                                type: string;
+                                additionalProperties: boolean;
+                                instanceof?: undefined;
+                              }
+                          )[];
+                        };
+                        instanceof?: undefined;
+                      }
+                    | {
+                        type: string;
+                        items?: undefined;
+                        instanceof?: undefined;
+                      }
+                    | {
+                        instanceof: string;
+                        type?: undefined;
+                        items?: undefined;
+                      }
+                  )[];
+                  description: string;
+                };
+              };
+              cli?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      HeaderObject: {
+        type: string;
+        additionalProperties: boolean;
+        properties: {
+          key: {
+            description: string;
+            type: string;
+          };
+          value: {
+            description: string;
+            type: string;
+          };
+        };
+        cli: {
+          exclude: boolean;
+        };
+      };
+      Headers: {
+        anyOf: (
+          | {
+              type: string;
+              items: {
+                $ref: string;
+              };
+              minItems: number;
+              instanceof?: undefined;
+            }
+          | {
+              type: string;
+              items?: undefined;
+              minItems?: undefined;
+              instanceof?: undefined;
+            }
+          | {
+              instanceof: string;
+              type?: undefined;
+              items?: undefined;
+              minItems?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      HistoryApiFallback: {
+        anyOf: (
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              description?: undefined;
+              link?: undefined;
+            }
+          | {
+              type: string;
+              description: string;
+              /** @type {{ type: WebSocketServerConfiguration["type"], options: NonNullable<WebSocketServerConfiguration["options"]> }} */
+              link: string;
+              cli?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      Host: {
+        description: string;
+        link: string;
+        anyOf: (
+          | {
+              enum: string[];
+              type?: undefined;
+              minLength?: undefined;
+            }
+          | {
+              type: string;
+              minLength: number;
+              enum?: undefined;
+            }
+        )[];
+      };
+      Hot: {
+        anyOf: (
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              enum?: undefined;
+            }
+          | {
+              enum: string[];
+              /** @type {string} */ type?: undefined;
+              cli?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      IPC: {
+        anyOf: (
+          | {
+              type: string;
+              minLength: number;
+              enum?: undefined;
+            }
+          | {
+              type: string;
+              enum: boolean[];
+              minLength?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      LiveReload: {
+        type: string;
+        description: string;
+        cli: {
+          negatedDescription: string;
+        };
+        link: string;
+      };
+      MagicHTML: {
+        type: string;
+        description: string;
+        cli: {
+          negatedDescription: string;
+        };
+        link: string;
+      };
+      OnAfterSetupMiddleware: {
+        instanceof: string;
+        description: string;
+        link: string;
+      };
+      OnBeforeSetupMiddleware: {
+        instanceof: string;
+        description: string;
+        link: string;
+      };
+      OnListening: {
+        instanceof: string;
+        description: string;
+        link: string;
+      };
+      Open: {
+        anyOf: (
+          | {
+              type: string;
+              items: {
+                anyOf: {
+                  $ref: string;
+                }[];
+              };
+              $ref?: undefined;
+            }
+          | {
+              $ref: string;
+              type?: undefined;
+              items?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      OpenBoolean: {
+        type: string;
+        cli: {
+          negatedDescription: string;
+        };
+      };
+      OpenObject: {
+        type: string;
+        additionalProperties: boolean;
+        properties: {
+          target: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    type: string;
+                  };
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          app: {
+            anyOf: (
+              | {
+                  type: string;
+                  additionalProperties: boolean;
+                  properties: {
+                    name: {
+                      anyOf: (
+                        | {
+                            type: string;
+                            items: {
+                              type: string;
+                              minLength: number;
+                            };
+                            minItems: number;
+                            minLength?: undefined;
+                          }
+                        | {
+                            type: string;
+                            minLength: number;
+                            items?: undefined;
+                            minItems?: undefined;
+                          }
+                      )[];
+                    };
+                    arguments: {
+                      items: {
+                        type: string;
+                        minLength: number;
+                      };
+                    };
+                  };
+                  minLength?: undefined;
+                  description?: undefined;
+                  cli?: undefined;
+                }
+              | {
+                  type: string;
+                  minLength: number;
+                  description: string;
+                  cli: {
+                    description: string;
+                  };
+                  additionalProperties?: undefined;
+                  properties?: undefined;
+                }
+            )[];
+            description: string;
+          };
+        };
+      };
+      OpenString: {
+        type: string;
+        minLength: number;
+      };
+      Port: {
+        anyOf: (
+          | {
+              type: string;
+              minimum: number;
+              maximum: number;
+              minLength?: undefined;
+              enum?: undefined;
+            }
+          | {
+              type: string;
+              minLength: number;
+              minimum?: undefined;
+              maximum?: undefined;
+              enum?: undefined;
+            }
+          | {
+              enum: string[];
+              type?: undefined;
+              minimum?: undefined;
+              maximum?: undefined;
+              minLength?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      Proxy: {
+        anyOf: (
+          | {
+              type: string;
+              items?: undefined;
+            }
+          | {
+              type: string;
+              items: {
+                anyOf: (
+                  | {
+                      type: string;
+                      instanceof?: undefined;
+                    }
+                  | {
+                      instanceof: string;
+                      type?: undefined;
+                    }
+                )[];
+              };
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      Server: {
+        anyOf: {
+          $ref: string;
+        }[];
+        link: string;
+        description: string;
+      };
+      ServerType: {
+        enum: string[];
+      };
+      ServerEnum: {
+        enum: string[];
+        cli: {
+          exclude: boolean;
+        };
+      };
+      ServerString: {
+        type: string;
+        /** @type {string} */ minLength: number;
+        cli: {
+          exclude: boolean;
+        };
+      };
+      ServerObject: {
+        type: string;
+        properties: {
+          type: {
+            anyOf: {
+              $ref: string;
+            }[];
+          };
+          options: {
+            $ref: string;
+          };
+        };
+        additionalProperties: boolean;
+      };
+      ServerOptions: {
+        type: string;
+        additionalProperties: boolean;
+        properties: {
+          passphrase: {
+            type: string;
+            description: string;
+          };
+          requestCert: {
+            type: string;
+            description: string;
+            cli: {
+              negatedDescription: string;
+            };
+          };
+          ca: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    anyOf: (
+                      | {
+                          type: string;
+                          instanceof?: undefined;
+                        }
+                      | {
+                          instanceof: string;
+                          type?: undefined;
+                        }
+                    )[];
+                  };
+                  instanceof?: undefined;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  instanceof?: undefined;
+                }
+              | {
+                  instanceof: string;
+                  type?: undefined;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          cacert: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    anyOf: (
+                      | {
+                          type: string;
+                          instanceof?: undefined;
+                        }
+                      | {
+                          instanceof: string;
+                          type?: undefined;
+                        }
+                    )[];
+                  };
+                  instanceof?: undefined;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  instanceof?: undefined;
+                }
+              | {
+                  instanceof: string;
+                  type?: undefined;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          cert: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    anyOf: (
+                      | {
+                          type: string;
+                          instanceof?: undefined;
+                        }
+                      | {
+                          instanceof: string;
+                          type?: undefined;
+                        }
+                    )[];
+                  };
+                  instanceof?: undefined;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  instanceof?: undefined;
+                }
+              | {
+                  instanceof: string;
+                  type?: undefined;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          crl: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    anyOf: (
+                      | {
+                          type: string;
+                          instanceof?: undefined;
+                        }
+                      | {
+                          instanceof: string;
+                          type?: undefined;
+                        }
+                    )[];
+                  };
+                  instanceof?: undefined;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  instanceof?: undefined;
+                }
+              | {
+                  instanceof: string;
+                  type?: undefined;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          key: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    anyOf: (
+                      | {
+                          type: string;
+                          instanceof?: undefined;
+                          additionalProperties?: undefined;
+                        }
+                      | {
+                          instanceof: string;
+                          type?: undefined;
+                          additionalProperties?: undefined;
+                        }
+                      | {
+                          type: string;
+                          additionalProperties: boolean;
+                          instanceof?: undefined;
+                        }
+                    )[];
+                  };
+                  instanceof?: undefined;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  instanceof?: undefined;
+                }
+              | {
+                  instanceof: string;
+                  type?: undefined;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          /** @type {NormalizedStatic} */
+          pfx: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    anyOf: (
+                      | {
+                          type: string;
+                          instanceof?: undefined;
+                          additionalProperties?: undefined;
+                        }
+                      | {
+                          instanceof: string;
+                          type?: undefined;
+                          additionalProperties?: undefined;
+                        }
+                      | {
+                          type: string;
+                          additionalProperties: boolean;
+                          instanceof?: undefined;
+                        }
+                    )[];
+                  };
+                  instanceof?: undefined;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  instanceof?: undefined;
+                }
+              | {
+                  instanceof: string;
+                  type?: undefined;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+        };
+      };
+      SetupExitSignals: {
+        type: string;
+        description: string;
+        link: string;
+        cli: {
+          exclude: boolean;
+        };
+      };
+      SetupMiddlewares: {
+        instanceof: string;
+        description: string;
+        link: string;
+      };
+      Static: {
+        anyOf: (
+          | {
+              type: string;
+              items: {
+                anyOf: {
+                  $ref: string;
+                }[];
+              };
+              cli?: undefined;
+              $ref?: undefined;
+            }
+          | {
+              type: string;
+              cli: {
+                negatedDescription: string;
+              };
+              items?: undefined;
+              $ref?: undefined;
+            }
+          | {
+              $ref: string;
+              type?: undefined;
+              items?: undefined;
+              cli?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      StaticObject: {
+        type: string;
+        additionalProperties: boolean;
+        properties: {
+          directory: {
+            type: string;
+            minLength: number;
+            description: string;
+            link: string;
+          };
+          staticOptions: {
+            type: string;
+            link: string;
+            additionalProperties: boolean;
+          };
+          publicPath: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    type: string;
+                  };
+                  minItems: number;
+                }
+              | {
+                  type: string;
+                  items?: undefined;
+                  minItems?: undefined;
+                }
+            )[];
+            description: string;
+            link: string;
+          };
+          serveIndex: {
+            anyOf: (
+              | {
+                  type: string;
+                  cli: {
+                    negatedDescription: string;
+                  };
+                  additionalProperties?: undefined;
+                }
+              | {
+                  type: string;
+                  additionalProperties: boolean;
+                  cli?: undefined;
+                }
+            )[];
+            description: string;
+            link: string;
+          };
+          watch: {
+            anyOf: (
+              | {
+                  type: string;
+                  cli: {
+                    negatedDescription: string;
+                  };
+                  description?: undefined;
+                  link?: undefined;
+                }
+              | {
+                  type: string;
+                  description: string;
+                  link: string;
+                  cli?: undefined;
+                }
+            )[];
+            description: string;
+            link: string;
+          };
+        };
+      };
+      StaticString: {
+        type: string;
+        minLength: number;
+      };
+      WatchFiles: {
+        anyOf: (
+          | {
+              type: string;
+              items: {
+                anyOf: {
+                  $ref: string;
+                }[];
+              };
+              $ref?: undefined;
+            }
+          | {
+              $ref: string;
+              type?: undefined;
+              items?: undefined;
+            }
+        )[];
+        description: string;
+        link: string;
+      };
+      WatchFilesObject: {
+        cli: {
+          exclude: boolean;
+        };
+        type: string;
+        properties: {
+          paths: {
+            anyOf: (
+              | {
+                  type: string;
+                  items: {
+                    type: string;
+                    minLength: number;
+                  };
+                  minLength?: undefined;
+                }
+              | {
+                  type: string;
+                  minLength: number;
+                  items?: undefined;
+                }
+            )[];
+            description: string;
+          };
+          options: {
+            type: string;
+            description: string;
+            link: string;
+            additionalProperties: boolean;
+          };
+        };
+        additionalProperties: boolean;
+      };
+      WatchFilesString: {
+        type: string;
+        minLength: number;
+      };
+      WebSocketServer: {
+        anyOf: {
+          $ref: string;
+        }[];
+        description: string;
+        link: string;
+      };
+      WebSocketServerType: {
+        enum: string[];
+      };
+      WebSocketServerEnum: {
+        anyOf: (
+          | {
+              enum: boolean[];
+              cli: {
+                negatedDescription: string;
+              };
+              $ref?: undefined;
+            }
+          | {
+              $ref: string;
+              enum?: undefined;
+              cli?: undefined;
+            }
+        )[];
+        cli: {
+          description: string;
+        };
+      };
+      WebSocketServerFunction: {
+        instanceof: string;
+      };
+      WebSocketServerObject: {
+        type: string;
+        properties: {
+          type: {
+            anyOf: {
+              $ref: string;
+            }[];
+          };
+          options: {
+            type: string;
+            additionalProperties: boolean;
+            cli: {
+              exclude: boolean;
+            };
+          };
+        };
+        additionalProperties: boolean;
+      };
+      WebSocketServerString: {
+        type: string;
+        minLength: number;
+      };
+    };
+    additionalProperties: boolean;
+    properties: {
+      allowedHosts: {
+        $ref: string;
+      };
+      bonjour: {
+        $ref: string;
+      };
+      client: {
+        $ref: string;
+      };
+      compress: {
+        $ref: string;
+      };
+      devMiddleware: {
+        $ref: string;
+      };
+      headers: {
+        $ref: string;
+      };
+      historyApiFallback: {
+        $ref: string;
+      };
+      host: {
+        $ref: string;
+      };
+      hot: {
+        $ref: string;
+      };
+      http2: {
+        $ref: string;
+      };
+      https: {
+        $ref: string;
+      };
+      ipc: {
+        $ref: string;
+      };
+      liveReload: {
+        $ref: string;
+      };
+      magicHtml: {
+        $ref: string;
+      };
+      onAfterSetupMiddleware: {
+        $ref: string;
+      };
+      onBeforeSetupMiddleware: {
+        $ref: string;
+      };
+      onListening: {
+        $ref: string;
+      };
+      open: {
+        $ref: string;
+      };
+      port: {
+        $ref: string;
+      };
+      proxy: {
+        $ref: string;
+      };
+      server: {
+        $ref: string;
+      };
+      setupExitSignals: {
+        $ref: string;
+      };
+      setupMiddlewares: {
+        $ref: string;
+      };
+      static: {
+        $ref: string;
+      };
+      watchFiles: {
+        $ref: string;
+      };
+      webSocketServer: {
+        $ref: string;
+      };
+    };
+  };
+  /**
+   * @param {string} URL
+   * @returns {boolean}
+   */
+  static isAbsoluteURL(URL: string): boolean;
+  /**
+   * @param {string} gateway
+   * @returns {string | undefined}
+   */
+  static findIp(gateway: string): string | undefined;
+  /**
+   * @param {"v4" | "v6"} family
+   * @returns {Promise<string | undefined>}
+   */
+  static internalIP(family: "v4" | "v6"): Promise<string | undefined>;
+  /**
+   * @param {"v4" | "v6"} family
+   * @returns {string | undefined}
+   */
+  static internalIPSync(family: "v4" | "v6"): string | undefined;
+  /**
+   * @param {Host} hostname
+   * @returns {Promise<string>}
+   */
+  static getHostname(hostname: Host): Promise<string>;
+  /**
+   * @param {Port} port
+   * @param {string} host
+   * @returns {Promise<number | string>}
+   */
+  static getFreePort(port: Port, host: string): Promise<number | string>;
+  /**
+   * @returns {string}
+   */
+  static findCacheDir(): string;
+  /**
+   * @private
+   * @param {Compiler} compiler
+   * @returns bool
+   */
+  private static isWebTarget;
+  /**
+   * @param {Configuration | Compiler | MultiCompiler} options
+   * @param {Compiler | MultiCompiler | Configuration} compiler
+   */
+  constructor(
+    options:
+      | import("webpack").Compiler
+      | import("webpack").MultiCompiler
+      | Configuration
+      | undefined,
+    compiler: Compiler | MultiCompiler | Configuration
+  );
+  compiler: import("webpack").Compiler | import("webpack").MultiCompiler;
+  /**
+   * @type {ReturnType<Compiler["getInfrastructureLogger"]>}
+   * */
+  logger: ReturnType<Compiler["getInfrastructureLogger"]>;
+  options: Configuration;
+  /**
+   * @type {FSWatcher[]}
+   */
+  staticWatchers: FSWatcher[];
+  /**
+   * @private
+   * @type {{ name: string | symbol, listener: (...args: any[]) => void}[] }}
+   */
+  private listeners;
+  /**
+   * @private
+   * @type {RequestHandler[]}
+   */
+  private webSocketProxies;
+  /**
+   * @type {Socket[]}
+   */
+  sockets: Socket[];
+  /**
+   * @private
+   * @type {string | undefined}
+   */
+  private currentHash;
+  /**
+   * @private
+   * @param {Compiler} compiler
+   */
+  private addAdditionalEntries;
+  /**
+   * @private
+   * @returns {Compiler["options"]}
+   */
+  private getCompilerOptions;
+  /**
+   * @private
+   * @returns {Promise<void>}
+   */
+  private normalizeOptions;
+  /**
+   * @private
+   * @returns {string}
+   */
+  private getClientTransport;
+  /**
+   * @private
+   * @returns {string}
+   */
+  private getServerTransport;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupProgressPlugin;
+  /**
+   * @private
+   * @returns {Promise<void>}
+   */
+  private initialize;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupApp;
+  /** @type {import("express").Application | undefined}*/
+  app: import("express").Application | undefined;
+  /**
+   * @private
+   * @param {Stats | MultiStats} statsObj
+   * @returns {StatsCompilation}
+   */
+  private getStats;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupHooks;
+  /**
+   * @private
+   * @type {Stats | MultiStats}
+   */
+  private stats;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupHostHeaderCheck;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupDevMiddleware;
+  middleware:
+    | import("webpack-dev-middleware").API<
+        import("express").Request<
+          import("express-serve-static-core").ParamsDictionary,
+          any,
+          any,
+          qs.ParsedQs,
+          Record<string, any>
+        >,
+        import("express").Response<any, Record<string, any>>
+      >
+    | null
+    | undefined;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupBuiltInRoutes;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupWatchStaticFiles;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupWatchFiles;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private setupMiddlewares;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private createServer;
+  /** @type {import("http").Server | undefined | null} */
+  server: import("http").Server | undefined | null;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private createWebSocketServer;
+  /** @type {WebSocketServerImplementation | undefined | null} */
+  webSocketServer: WebSocketServerImplementation | undefined | null;
+  /**
+   * @private
+   * @param {string} defaultOpenTarget
+   * @returns {void}
+   */
+  private openBrowser;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private runBonjour;
+  /**
+   * @private
+   * @type {Bonjour | undefined}
+   */
+  private bonjour;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private stopBonjour;
+  /**
+   * @private
+   * @returns {void}
+   */
+  private logStatus;
+  /**
+   * @private
+   * @param {Request} req
+   * @param {Response} res
+   * @param {NextFunction} next
+   */
+  private setHeaders;
+  /**
+   * @private
+   * @param {{ [key: string]: string | undefined }} headers
+   * @param {string} headerToCheck
+   * @returns {boolean}
+   */
+  private checkHeader;
+  /**
+   * @param {ClientConnection[]} clients
+   * @param {string} type
+   * @param {any} [data]
+   * @param {any} [params]
+   */
+  sendMessage(
+    clients: ClientConnection[],
+    type: string,
+    data?: any,
+    params?: any
+  ): void;
+  /**
+   * @private
+   * @param {Request} req
+   * @param {Response} res
+   * @param {NextFunction} next
+   * @returns {void}
+   */
+  private serveMagicHtml;
+  /**
+   * @private
+   * @param {ClientConnection[]} clients
+   * @param {StatsCompilation} stats
+   * @param {boolean} [force]
+   */
+  private sendStats;
+  /**
+   * @param {string | string[]} watchPath
+   * @param {WatchOptions} [watchOptions]
+   */
+  watchFiles(
+    watchPath: string | string[],
+    watchOptions?: import("chokidar").WatchOptions | undefined
+  ): void;
+  /**
+   * @param {import("webpack-dev-middleware").Callback} [callback]
+   */
+  invalidate(
+    callback?: import("webpack-dev-middleware").Callback | undefined
+  ): void;
+  /**
+   * @returns {Promise<void>}
+   */
+  start(): Promise<void>;
+  /**
+   * @param {(err?: Error) => void} [callback]
+   */
+  startCallback(callback?: ((err?: Error) => void) | undefined): void;
+  /**
+   * @returns {Promise<void>}
+   */
+  stop(): Promise<void>;
+  /**
+   * @param {(err?: Error) => void} [callback]
+   */
+  stopCallback(callback?: ((err?: Error) => void) | undefined): void;
+  /**
+   * @param {Port} port
+   * @param {Host} hostname
+   * @param {(err?: Error) => void} fn
+   * @returns {void}
+   */
+  listen(port: Port, hostname: Host, fn: (err?: Error) => void): void;
+  /**
+   * @param {(err?: Error) => void} [callback]
+   * @returns {void}
+   */
+  close(callback?: ((err?: Error) => void) | undefined): void;
+}
+declare namespace Server {
+  export {
+    DEFAULT_STATS,
+    Schema,
+    Compiler,
+    MultiCompiler,
+    WebpackConfiguration,
+    StatsOptions,
+    StatsCompilation,
+    Stats,
+    MultiStats,
+    NetworkInterfaceInfo,
+    Request,
+    Response,
+    NextFunction,
+    ExpressRequestHandler,
+    ExpressErrorRequestHandler,
+    WatchOptions,
+    FSWatcher,
+    ConnectHistoryApiFallbackOptions,
+    Bonjour,
+    BonjourOptions,
+    RequestHandler,
+    HttpProxyMiddlewareOptions,
+    HttpProxyMiddlewareOptionsFilter,
+    ServeIndexOptions,
+    ServeStaticOptions,
+    IPv4,
+    IPv6,
+    Socket,
+    IncomingMessage,
+    OpenOptions,
+    ServerOptions,
+    DevMiddlewareOptions,
+    DevMiddlewareContext,
+    Host,
+    Port,
+    WatchFiles,
+    Static,
+    NormalizedStatic,
+    ServerConfiguration,
+    WebSocketServerConfiguration,
+    ClientConnection,
+    WebSocketServer,
+    WebSocketServerImplementation,
+    ByPass,
+    ProxyConfigArrayItem,
+    ProxyConfigArray,
+    ProxyConfigMap,
+    OpenApp,
+    Open,
+    NormalizedOpen,
+    WebSocketURL,
+    OverlayMessageOptions,
+    ClientConfiguration,
+    Headers,
+    Middleware,
+    Configuration,
+  };
+}
+type Compiler = import("webpack").Compiler;
+type Configuration = {
+  ipc?: string | boolean | undefined;
+  host?: string | undefined;
+  port?: Port | undefined;
+  hot?: boolean | "only" | undefined;
+  liveReload?: boolean | undefined;
+  devMiddleware?:
+    | DevMiddlewareOptions<
+        import("express").Request<
+          import("express-serve-static-core").ParamsDictionary,
+          any,
+          any,
+          qs.ParsedQs,
+          Record<string, any>
+        >,
+        import("express").Response<any, Record<string, any>>
+      >
+    | undefined;
+  compress?: boolean | undefined;
+  magicHtml?: boolean | undefined;
+  allowedHosts?: string | string[] | undefined;
+  historyApiFallback?:
+    | boolean
+    | import("connect-history-api-fallback").Options
+    | undefined;
+  bonjour?:
+    | boolean
+    | Record<string, never>
+    | import("bonjour-service").Service
+    | undefined;
+  watchFiles?:
+    | string
+    | string[]
+    | WatchFiles
+    | (string | WatchFiles)[]
+    | undefined;
+  static?: string | boolean | Static | (string | Static)[] | undefined;
+  https?: boolean | ServerOptions | undefined;
+  http2?: boolean | undefined;
+  server?: string | ServerConfiguration | undefined;
+  webSocketServer?: string | boolean | WebSocketServerConfiguration | undefined;
+  proxy?: ProxyConfigArrayItem | ProxyConfigMap | ProxyConfigArray | undefined;
+  open?: string | boolean | Open | (string | Open)[] | undefined;
+  setupExitSignals?: boolean | undefined;
+  client?: boolean | ClientConfiguration | undefined;
+  headers?:
+    | Headers
+    | ((
+        req: Request,
+        res: Response,
+        context: DevMiddlewareContext<Request, Response>
+      ) => Headers)
+    | undefined;
+  onAfterSetupMiddleware?: ((devServer: Server) => void) | undefined;
+  onBeforeSetupMiddleware?: ((devServer: Server) => void) | undefined;
+  onListening?: ((devServer: Server) => void) | undefined;
+  setupMiddlewares?:
+    | ((middlewares: Middleware[], devServer: Server) => Middleware[])
+    | undefined;
+};
+type FSWatcher = import("chokidar").FSWatcher;
+type Socket = import("net").Socket;
+type WebSocketServerImplementation = {
+  implementation: WebSocketServer;
+  clients: ClientConnection[];
+};
+type ClientConnection = (
+  | import("ws").WebSocket
+  | (import("sockjs").Connection & {
+      send: import("ws").WebSocket["send"];
+      terminate: import("ws").WebSocket["terminate"];
+      ping: import("ws").WebSocket["ping"];
+    })
+) & {
+  isAlive?: boolean;
+};
+type Port = number | string | "auto";
+type Host = "local-ip" | "local-ipv4" | "local-ipv6" | string;
+type MultiCompiler = import("webpack").MultiCompiler;
+declare class DEFAULT_STATS {
+  private constructor();
+}
+type Schema = import("schema-utils/declarations/validate").Schema;
+type WebpackConfiguration = import("webpack").Configuration;
+type StatsOptions = import("webpack").StatsOptions;
+type StatsCompilation = import("webpack").StatsCompilation;
+type Stats = import("webpack").Stats;
+type MultiStats = import("webpack").MultiStats;
+type NetworkInterfaceInfo = import("os").NetworkInterfaceInfo;
+type Request = import("express").Request;
+type Response = import("express").Response;
+type NextFunction = import("express").NextFunction;
+type ExpressRequestHandler = import("express").RequestHandler;
+type ExpressErrorRequestHandler = import("express").ErrorRequestHandler;
+type WatchOptions = import("chokidar").WatchOptions;
+type ConnectHistoryApiFallbackOptions =
+  import("connect-history-api-fallback").Options;
+type Bonjour = import("bonjour-service").Bonjour;
+type BonjourOptions = import("bonjour-service").Service;
+type RequestHandler = import("http-proxy-middleware").RequestHandler;
+type HttpProxyMiddlewareOptions = import("http-proxy-middleware").Options;
+type HttpProxyMiddlewareOptionsFilter = import("http-proxy-middleware").Filter;
+type ServeIndexOptions = import("serve-index").Options;
+type ServeStaticOptions = import("serve-static").ServeStaticOptions;
+type IPv4 = import("ipaddr.js").IPv4;
+type IPv6 = import("ipaddr.js").IPv6;
+type IncomingMessage = import("http").IncomingMessage;
+type OpenOptions = import("open").Options;
+type ServerOptions = import("https").ServerOptions & {
+  spdy?: {
+    plain?: boolean | undefined;
+    ssl?: boolean | undefined;
+    "x-forwarded-for"?: string | undefined;
+    protocol?: string | undefined;
+    protocols?: string[] | undefined;
+  };
+};
+type DevMiddlewareOptions<Request_1, Response_1> =
+  import("webpack-dev-middleware").Options<Request, Response>;
+type DevMiddlewareContext<Request_1, Response_1> =
+  import("webpack-dev-middleware").Context<Request, Response>;
+type WatchFiles = {
+  paths: string | string[];
+  options?:
+    | (import("chokidar").WatchOptions & {
+        aggregateTimeout?: number | undefined;
+        ignored?: WatchOptions["ignored"];
+        poll?: number | boolean | undefined;
+      })
+    | undefined;
+};
+type Static = {
+  directory?: string | undefined;
+  publicPath?: string | string[] | undefined;
+  serveIndex?: boolean | import("serve-index").Options | undefined;
+  staticOptions?:
+    | import("serve-static").ServeStaticOptions<
+        import("http").ServerResponse<import("http").IncomingMessage>
+      >
+    | undefined;
+  watch?:
+    | boolean
+    | (import("chokidar").WatchOptions & {
+        aggregateTimeout?: number | undefined;
+        ignored?: WatchOptions["ignored"];
+        poll?: number | boolean | undefined;
+      })
+    | undefined;
+};
+type NormalizedStatic = {
+  directory: string;
+  publicPath: string[];
+  serveIndex: false | ServeIndexOptions;
+  staticOptions: ServeStaticOptions;
+  watch: false | WatchOptions;
+};
+type ServerConfiguration = {
+  type?: string | undefined;
+  options?: ServerOptions | undefined;
+};
+type WebSocketServerConfiguration = {
+  type?: string | Function | undefined;
+  options?: Record<string, any> | undefined;
+};
+type WebSocketServer =
+  | import("ws").WebSocketServer
+  | (import("sockjs").Server & {
+      close: import("ws").WebSocketServer["close"];
+    });
+type ByPass = (
+  req: Request,
+  res: Response,
+  proxyConfig: ProxyConfigArrayItem
+) => any;
+type ProxyConfigArrayItem = {
+  path?: HttpProxyMiddlewareOptionsFilter | undefined;
+  context?: HttpProxyMiddlewareOptionsFilter | undefined;
+} & {
+  bypass?: ByPass;
+} & HttpProxyMiddlewareOptions;
+type ProxyConfigArray = (
+  | ProxyConfigArrayItem
+  | ((
+      req?: Request | undefined,
+      res?: Response | undefined,
+      next?: NextFunction | undefined
+    ) => ProxyConfigArrayItem)
+)[];
+type ProxyConfigMap = {
+  [url: string]: string | ProxyConfigArrayItem;
+};
+type OpenApp = {
+  name?: string | undefined;
+  arguments?: string[] | undefined;
+};
+type Open = {
+  app?: string | string[] | OpenApp | undefined;
+  target?: string | string[] | undefined;
+};
+type NormalizedOpen = {
+  target: string;
+  options: import("open").Options;
+};
+type WebSocketURL = {
+  hostname?: string | undefined;
+  password?: string | undefined;
+  pathname?: string | undefined;
+  port?: string | number | undefined;
+  protocol?: string | undefined;
+  username?: string | undefined;
+};
+type OverlayMessageOptions = boolean | ((error: Error) => void);
+type ClientConfiguration = {
+  logging?: "none" | "error" | "warn" | "info" | "log" | "verbose" | undefined;
+  overlay?:
+    | boolean
+    | {
+        warnings?: OverlayMessageOptions | undefined;
+        errors?: OverlayMessageOptions | undefined;
+        runtimeErrors?: OverlayMessageOptions | undefined;
+      }
+    | undefined;
+  progress?: boolean | undefined;
+  reconnect?: number | boolean | undefined;
+  webSocketTransport?: string | undefined;
+  webSocketURL?: string | WebSocketURL | undefined;
+};
+type Headers =
+  | Array<{
+      key: string;
+      value: string;
+    }>
+  | Record<string, string | string[]>;
+type Middleware =
+  | {
+      name?: string;
+      path?: string;
+      middleware: ExpressRequestHandler | ExpressErrorRequestHandler;
+    }
+  | ExpressRequestHandler
+  | ExpressErrorRequestHandler;
+import path = require("path");
+
+// DO NOT REMOVE THIS!
+type DevServerConfiguration = Configuration;
+declare module "webpack" {
+  interface Configuration {
+    /**
+     * Can be used to configure the behaviour of webpack-dev-server when
+     * the webpack config is passed to webpack-dev-server CLI.
+     */
+    devServer?: DevServerConfiguration | undefined;
+  }
+}
Index: frontend/node_modules/webpack-dev-server/types/lib/getPort.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/lib/getPort.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/lib/getPort.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,10 @@
+export = getPorts;
+/**
+ * @param {number} basePort
+ * @param {string=} host
+ * @return {Promise<number>}
+ */
+declare function getPorts(
+  basePort: number,
+  host?: string | undefined
+): Promise<number>;
Index: frontend/node_modules/webpack-dev-server/types/lib/servers/BaseServer.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/lib/servers/BaseServer.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/lib/servers/BaseServer.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+export = BaseServer;
+declare class BaseServer {
+  /**
+   * @param {import("../Server")} server
+   */
+  constructor(server: import("../Server"));
+  /** @type {import("../Server")} */
+  server: import("../Server");
+  /** @type {ClientConnection[]} */
+  clients: ClientConnection[];
+}
+declare namespace BaseServer {
+  export { ClientConnection };
+}
+type ClientConnection = import("../Server").ClientConnection;
Index: frontend/node_modules/webpack-dev-server/types/lib/servers/SockJSServer.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/lib/servers/SockJSServer.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/lib/servers/SockJSServer.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+export = SockJSServer;
+declare class SockJSServer extends BaseServer {
+  implementation: sockjs.Server;
+}
+declare namespace SockJSServer {
+  export { WebSocketServerConfiguration, ClientConnection };
+}
+import BaseServer = require("./BaseServer");
+import sockjs = require("sockjs");
+type WebSocketServerConfiguration =
+  import("../Server").WebSocketServerConfiguration;
+type ClientConnection = import("../Server").ClientConnection;
Index: frontend/node_modules/webpack-dev-server/types/lib/servers/WebsocketServer.d.ts
===================================================================
--- frontend/node_modules/webpack-dev-server/types/lib/servers/WebsocketServer.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/webpack-dev-server/types/lib/servers/WebsocketServer.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+/// <reference types="node" />
+export = WebsocketServer;
+declare class WebsocketServer extends BaseServer {
+  static heartbeatInterval: number;
+  implementation: WebSocket.Server<
+    typeof WebSocket,
+    typeof import("http").IncomingMessage
+  >;
+}
+declare namespace WebsocketServer {
+  export { WebSocketServerConfiguration, ClientConnection };
+}
+import BaseServer = require("./BaseServer");
+import WebSocket = require("ws");
+type WebSocketServerConfiguration =
+  import("../Server").WebSocketServerConfiguration;
+type ClientConnection = import("../Server").ClientConnection;
