Index: frontend/node_modules/loader-utils/LICENSE
===================================================================
--- frontend/node_modules/loader-utils/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/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/loader-utils/README.md
===================================================================
--- frontend/node_modules/loader-utils/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,275 @@
+# loader-utils
+
+## Methods
+
+### `getOptions`
+
+Recommended way to retrieve the options of a loader invocation:
+
+```javascript
+// inside your loader
+const options = loaderUtils.getOptions(this);
+```
+
+1. If `this.query` is a string:
+	- Tries to parse the query string and returns a new object
+	- Throws if it's not a valid query string
+2. If `this.query` is object-like, it just returns `this.query`
+3. In any other case, it just returns `null`
+
+**Please note:** The returned `options` object is *read-only*. It may be re-used across multiple invocations.
+If you pass it on to another library, make sure to make a *deep copy* of it:
+
+```javascript
+const options = Object.assign(
+	{},
+	defaultOptions,
+	loaderUtils.getOptions(this) // it is safe to pass null to Object.assign()
+);
+// don't forget nested objects or arrays
+options.obj = Object.assign({}, options.obj); 
+options.arr = options.arr.slice();
+someLibrary(options);
+```
+
+[clone](https://www.npmjs.com/package/clone) is a good library to make a deep copy of the options.
+
+#### Options as query strings
+
+If the loader options have been passed as loader query string (`loader?some&params`), the string is parsed by using [`parseQuery`](#parsequery).
+
+### `parseQuery`
+
+Parses a passed string (e.g. `loaderContext.resourceQuery`) as a query string, and returns an object.
+
+``` javascript
+const params = loaderUtils.parseQuery(this.resourceQuery); // resource: `file?param1=foo`
+if (params.param1 === "foo") {
+	// do something
+}
+```
+
+The string is parsed like this:
+
+``` text
+                             -> Error
+?                            -> {}
+?flag                        -> { flag: true }
+?+flag                       -> { flag: true }
+?-flag                       -> { flag: false }
+?xyz=test                    -> { xyz: "test" }
+?xyz=1                       -> { xyz: "1" } // numbers are NOT parsed
+?xyz[]=a                     -> { xyz: ["a"] }
+?flag1&flag2                 -> { flag1: true, flag2: true }
+?+flag1,-flag2               -> { flag1: true, flag2: false }
+?xyz[]=a,xyz[]=b             -> { xyz: ["a", "b"] }
+?a%2C%26b=c%2C%26d           -> { "a,&b": "c,&d" }
+?{data:{a:1},isJSON5:true}   -> { data: { a: 1 }, isJSON5: true }
+```
+
+### `stringifyRequest`
+
+Turns a request into a string that can be used inside `require()` or `import` while avoiding absolute paths.
+Use it instead of `JSON.stringify(...)` if you're generating code inside a loader.
+
+**Why is this necessary?** Since webpack calculates the hash before module paths are translated into module ids, we must avoid absolute paths to ensure
+consistent hashes across different compilations.
+
+This function:
+
+- resolves absolute requests into relative requests if the request and the module are on the same hard drive
+- replaces `\` with `/` if the request and the module are on the same hard drive
+- won't change the path at all if the request and the module are on different hard drives
+- applies `JSON.stringify` to the result
+
+```javascript
+loaderUtils.stringifyRequest(this, "./test.js");
+// "\"./test.js\""
+
+loaderUtils.stringifyRequest(this, ".\\test.js");
+// "\"./test.js\""
+
+loaderUtils.stringifyRequest(this, "test");
+// "\"test\""
+
+loaderUtils.stringifyRequest(this, "test/lib/index.js");
+// "\"test/lib/index.js\""
+
+loaderUtils.stringifyRequest(this, "otherLoader?andConfig!test?someConfig");
+// "\"otherLoader?andConfig!test?someConfig\""
+
+loaderUtils.stringifyRequest(this, require.resolve("test"));
+// "\"../node_modules/some-loader/lib/test.js\""
+
+loaderUtils.stringifyRequest(this, "C:\\module\\test.js");
+// "\"../../test.js\"" (on Windows, in case the module and the request are on the same drive)
+
+loaderUtils.stringifyRequest(this, "C:\\module\\test.js");
+// "\"C:\\module\\test.js\"" (on Windows, in case the module and the request are on different drives)
+
+loaderUtils.stringifyRequest(this, "\\\\network-drive\\test.js");
+// "\"\\\\network-drive\\\\test.js\"" (on Windows, in case the module and the request are on different drives)
+```
+
+### `urlToRequest`
+
+Converts some resource URL to a webpack module request.
+
+> i Before call `urlToRequest` you need call `isUrlRequest` to ensure it is requestable url
+
+```javascript
+const url = "path/to/module.js";
+
+if (loaderUtils.isUrlRequest(url)) {
+  // Logic for requestable url
+  const request = loaderUtils.urlToRequest(url);
+} else {
+  // Logic for not requestable url
+}
+```
+
+Simple example:
+
+```javascript
+const url = "path/to/module.js";
+const request = loaderUtils.urlToRequest(url); // "./path/to/module.js"
+```
+
+#### Module URLs
+
+Any URL containing a `~` will be interpreted as a module request. Anything after the `~` will be considered the request path.
+
+```javascript
+const url = "~path/to/module.js";
+const request = loaderUtils.urlToRequest(url); // "path/to/module.js"
+```
+
+#### Root-relative URLs
+
+URLs that are root-relative (start with `/`) can be resolved relative to some arbitrary path by using the `root` parameter:
+
+```javascript
+const url = "/path/to/module.js";
+const root = "./root";
+const request = loaderUtils.urlToRequest(url, root); // "./root/path/to/module.js"
+```
+
+To convert a root-relative URL into a module URL, specify a `root` value that starts with `~`:
+
+```javascript
+const url = "/path/to/module.js";
+const root = "~";
+const request = loaderUtils.urlToRequest(url, root); // "path/to/module.js"
+```
+
+### `interpolateName`
+
+Interpolates a filename template using multiple placeholders and/or a regular expression.
+The template and regular expression are set as query params called `name` and `regExp` on the current loader's context.
+
+```javascript
+const interpolatedName = loaderUtils.interpolateName(loaderContext, name, options);
+```
+
+The following tokens are replaced in the `name` parameter:
+
+* `[ext]` the extension of the resource
+* `[name]` the basename of the resource
+* `[path]` the path of the resource relative to the `context` query parameter or option.
+* `[folder]` the folder the resource is in
+* `[query]` the queryof the resource, i.e. `?foo=bar`
+* `[emoji]` a random emoji representation of `options.content`
+* `[emoji:<length>]` same as above, but with a customizable number of emojis
+* `[contenthash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the md4 hash)
+* `[<hashType>:contenthash:<digestType>:<length>]` optionally one can configure
+  * other `hashType`s, i. e. `sha1`, `md4`, `md5`, `sha256`, `sha512`
+  * other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
+  * and `length` the length in chars
+* `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the md4 hash)
+* `[<hashType>:hash:<digestType>:<length>]` optionally one can configure
+  * other `hashType`s, i. e. `sha1`, `md4`, `md5`, `sha256`, `sha512`
+  * other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
+  * and `length` the length in chars
+* `[N]` the N-th match obtained from matching the current file name against `options.regExp`
+
+In loader context `[hash]` and `[contenthash]` are the same, but we recommend using `[contenthash]` for avoid misleading.
+
+Examples
+
+``` javascript
+// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
+loaderUtils.interpolateName(loaderContext, "js/[hash].script.[ext]", { content: ... });
+// => js/9473fdd0d880a43c21b7778d34872157.script.js
+
+// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
+// loaderContext.resourceQuery = "?foo=bar"
+loaderUtils.interpolateName(loaderContext, "js/[hash].script.[ext][query]", { content: ... });
+// => js/9473fdd0d880a43c21b7778d34872157.script.js?foo=bar
+
+// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
+loaderUtils.interpolateName(loaderContext, "js/[contenthash].script.[ext]", { content: ... });
+// => js/9473fdd0d880a43c21b7778d34872157.script.js
+
+// loaderContext.resourcePath = "/absolute/path/to/app/page.html"
+loaderUtils.interpolateName(loaderContext, "html-[hash:6].html", { content: ... });
+// => html-9473fd.html
+
+// loaderContext.resourcePath = "/absolute/path/to/app/flash.txt"
+loaderUtils.interpolateName(loaderContext, "[hash]", { content: ... });
+// => c31e9820c001c9c4a86bce33ce43b679
+
+// loaderContext.resourcePath = "/absolute/path/to/app/img/image.gif"
+loaderUtils.interpolateName(loaderContext, "[emoji]", { content: ... });
+// => 👍
+
+// loaderContext.resourcePath = "/absolute/path/to/app/img/image.gif"
+loaderUtils.interpolateName(loaderContext, "[emoji:4]", { content: ... });
+// => 🙍🏢📤🐝
+
+// loaderContext.resourcePath = "/absolute/path/to/app/img/image.png"
+loaderUtils.interpolateName(loaderContext, "[sha512:hash:base64:7].[ext]", { content: ... });
+// => 2BKDTjl.png
+// use sha512 hash instead of md4 and with only 7 chars of base64
+
+// loaderContext.resourcePath = "/absolute/path/to/app/img/myself.png"
+// loaderContext.query.name =
+loaderUtils.interpolateName(loaderContext, "picture.png");
+// => picture.png
+
+// loaderContext.resourcePath = "/absolute/path/to/app/dir/file.png"
+loaderUtils.interpolateName(loaderContext, "[path][name].[ext]?[hash]", { content: ... });
+// => /app/dir/file.png?9473fdd0d880a43c21b7778d34872157
+
+// loaderContext.resourcePath = "/absolute/path/to/app/js/page-home.js"
+loaderUtils.interpolateName(loaderContext, "script-[1].[ext]", { regExp: "page-(.*)\\.js", content: ... });
+// => script-home.js
+
+// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
+// loaderContext.resourceQuery = "?foo=bar"
+loaderUtils.interpolateName(
+  loaderContext, 
+  (resourcePath, resourceQuery) => { 
+    // resourcePath - `/app/js/javascript.js`
+    // resourceQuery - `?foo=bar`
+
+    return "js/[hash].script.[ext]"; 
+  }, 
+  { content: ... }
+);
+// => js/9473fdd0d880a43c21b7778d34872157.script.js
+```
+
+### `getHashDigest`
+
+``` javascript
+const digestString = loaderUtils.getHashDigest(buffer, hashType, digestType, maxLength);
+```
+
+* `buffer` the content that should be hashed
+* `hashType` one of `sha1`, `md4`, `md5`, `sha256`, `sha512` or any other node.js supported hash type
+* `digestType` one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
+* `maxLength` the maximum length in chars
+
+## License
+
+MIT (http://www.opensource.org/licenses/mit-license.php)
Index: frontend/node_modules/loader-utils/lib/getCurrentRequest.js
===================================================================
--- frontend/node_modules/loader-utils/lib/getCurrentRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/getCurrentRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+'use strict';
+
+function getCurrentRequest(loaderContext) {
+  if (loaderContext.currentRequest) {
+    return loaderContext.currentRequest;
+  }
+
+  const request = loaderContext.loaders
+    .slice(loaderContext.loaderIndex)
+    .map((obj) => obj.request)
+    .concat([loaderContext.resource]);
+
+  return request.join('!');
+}
+
+module.exports = getCurrentRequest;
Index: frontend/node_modules/loader-utils/lib/getHashDigest.js
===================================================================
--- frontend/node_modules/loader-utils/lib/getHashDigest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/getHashDigest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,91 @@
+'use strict';
+
+const baseEncodeTables = {
+  26: 'abcdefghijklmnopqrstuvwxyz',
+  32: '123456789abcdefghjkmnpqrstuvwxyz', // no 0lio
+  36: '0123456789abcdefghijklmnopqrstuvwxyz',
+  49: 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', // no lIO
+  52: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
+  58: '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', // no 0lIO
+  62: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
+  64: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
+};
+
+function encodeBufferToBase(buffer, base) {
+  const encodeTable = baseEncodeTables[base];
+  if (!encodeTable) {
+    throw new Error('Unknown encoding base' + base);
+  }
+
+  const readLength = buffer.length;
+  const Big = require('big.js');
+
+  Big.RM = Big.DP = 0;
+  let b = new Big(0);
+
+  for (let i = readLength - 1; i >= 0; i--) {
+    b = b.times(256).plus(buffer[i]);
+  }
+
+  let output = '';
+  while (b.gt(0)) {
+    output = encodeTable[b.mod(base)] + output;
+    b = b.div(base);
+  }
+
+  Big.DP = 20;
+  Big.RM = 1;
+
+  return output;
+}
+
+let createMd4 = undefined;
+let BatchedHash = undefined;
+
+function getHashDigest(buffer, hashType, digestType, maxLength) {
+  hashType = hashType || 'md4';
+  maxLength = maxLength || 9999;
+
+  let hash;
+
+  try {
+    hash = require('crypto').createHash(hashType);
+  } catch (error) {
+    if (error.code === 'ERR_OSSL_EVP_UNSUPPORTED' && hashType === 'md4') {
+      if (createMd4 === undefined) {
+        createMd4 = require('./hash/md4');
+
+        if (BatchedHash === undefined) {
+          BatchedHash = require('./hash/BatchedHash');
+        }
+      }
+
+      hash = new BatchedHash(createMd4());
+    }
+
+    if (!hash) {
+      throw error;
+    }
+  }
+
+  hash.update(buffer);
+
+  if (
+    digestType === 'base26' ||
+    digestType === 'base32' ||
+    digestType === 'base36' ||
+    digestType === 'base49' ||
+    digestType === 'base52' ||
+    digestType === 'base58' ||
+    digestType === 'base62'
+  ) {
+    return encodeBufferToBase(hash.digest(), digestType.substr(4)).substr(
+      0,
+      maxLength
+    );
+  } else {
+    return hash.digest(digestType || 'hex').substr(0, maxLength);
+  }
+}
+
+module.exports = getHashDigest;
Index: frontend/node_modules/loader-utils/lib/getOptions.js
===================================================================
--- frontend/node_modules/loader-utils/lib/getOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/getOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+'use strict';
+
+const parseQuery = require('./parseQuery');
+
+function getOptions(loaderContext) {
+  const query = loaderContext.query;
+
+  if (typeof query === 'string' && query !== '') {
+    return parseQuery(loaderContext.query);
+  }
+
+  if (!query || typeof query !== 'object') {
+    // Not object-like queries are not supported.
+    return {};
+  }
+
+  return query;
+}
+
+module.exports = getOptions;
Index: frontend/node_modules/loader-utils/lib/getRemainingRequest.js
===================================================================
--- frontend/node_modules/loader-utils/lib/getRemainingRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/getRemainingRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+'use strict';
+
+function getRemainingRequest(loaderContext) {
+  if (loaderContext.remainingRequest) {
+    return loaderContext.remainingRequest;
+  }
+
+  const request = loaderContext.loaders
+    .slice(loaderContext.loaderIndex + 1)
+    .map((obj) => obj.request)
+    .concat([loaderContext.resource]);
+
+  return request.join('!');
+}
+
+module.exports = getRemainingRequest;
Index: frontend/node_modules/loader-utils/lib/hash/BatchedHash.js
===================================================================
--- frontend/node_modules/loader-utils/lib/hash/BatchedHash.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/hash/BatchedHash.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+const MAX_SHORT_STRING = require('./wasm-hash').MAX_SHORT_STRING;
+
+class BatchedHash {
+  constructor(hash) {
+    this.string = undefined;
+    this.encoding = undefined;
+    this.hash = hash;
+  }
+
+  /**
+   * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
+   * @param {string|Buffer} data data
+   * @param {string=} inputEncoding data encoding
+   * @returns {this} updated hash
+   */
+  update(data, inputEncoding) {
+    if (this.string !== undefined) {
+      if (
+        typeof data === 'string' &&
+        inputEncoding === this.encoding &&
+        this.string.length + data.length < MAX_SHORT_STRING
+      ) {
+        this.string += data;
+
+        return this;
+      }
+
+      this.hash.update(this.string, this.encoding);
+      this.string = undefined;
+    }
+
+    if (typeof data === 'string') {
+      if (
+        data.length < MAX_SHORT_STRING &&
+        // base64 encoding is not valid since it may contain padding chars
+        (!inputEncoding || !inputEncoding.startsWith('ba'))
+      ) {
+        this.string = data;
+        this.encoding = inputEncoding;
+      } else {
+        this.hash.update(data, inputEncoding);
+      }
+    } else {
+      this.hash.update(data);
+    }
+
+    return this;
+  }
+
+  /**
+   * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
+   * @param {string=} encoding encoding of the return value
+   * @returns {string|Buffer} digest
+   */
+  digest(encoding) {
+    if (this.string !== undefined) {
+      this.hash.update(this.string, this.encoding);
+    }
+
+    return this.hash.digest(encoding);
+  }
+}
+
+module.exports = BatchedHash;
Index: frontend/node_modules/loader-utils/lib/hash/md4.js
===================================================================
--- frontend/node_modules/loader-utils/lib/hash/md4.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/hash/md4.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+
+'use strict';
+
+const create = require('./wasm-hash');
+
+//#region wasm code: md4 (../../../assembly/hash/md4.asm.ts) --initialMemory 1
+const md4 = new WebAssembly.Module(
+  Buffer.from(
+    // 2150 bytes
+    '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',
+    'base64'
+  )
+);
+//#endregion
+
+module.exports = create.bind(null, md4, [], 64, 32);
Index: frontend/node_modules/loader-utils/lib/hash/wasm-hash.js
===================================================================
--- frontend/node_modules/loader-utils/lib/hash/wasm-hash.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/hash/wasm-hash.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,208 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+
+'use strict';
+
+// 65536 is the size of a wasm memory page
+// 64 is the maximum chunk size for every possible wasm hash implementation
+// 4 is the maximum number of bytes per char for string encoding (max is utf-8)
+// ~3 makes sure that it's always a block of 4 chars, so avoid partially encoded bytes for base64
+const MAX_SHORT_STRING = Math.floor((65536 - 64) / 4) & ~3;
+
+class WasmHash {
+  /**
+   * @param {WebAssembly.Instance} instance wasm instance
+   * @param {WebAssembly.Instance[]} instancesPool pool of instances
+   * @param {number} chunkSize size of data chunks passed to wasm
+   * @param {number} digestSize size of digest returned by wasm
+   */
+  constructor(instance, instancesPool, chunkSize, digestSize) {
+    const exports = /** @type {any} */ (instance.exports);
+
+    exports.init();
+
+    this.exports = exports;
+    this.mem = Buffer.from(exports.memory.buffer, 0, 65536);
+    this.buffered = 0;
+    this.instancesPool = instancesPool;
+    this.chunkSize = chunkSize;
+    this.digestSize = digestSize;
+  }
+
+  reset() {
+    this.buffered = 0;
+    this.exports.init();
+  }
+
+  /**
+   * @param {Buffer | string} data data
+   * @param {BufferEncoding=} encoding encoding
+   * @returns {this} itself
+   */
+  update(data, encoding) {
+    if (typeof data === 'string') {
+      while (data.length > MAX_SHORT_STRING) {
+        this._updateWithShortString(data.slice(0, MAX_SHORT_STRING), encoding);
+        data = data.slice(MAX_SHORT_STRING);
+      }
+
+      this._updateWithShortString(data, encoding);
+
+      return this;
+    }
+
+    this._updateWithBuffer(data);
+
+    return this;
+  }
+
+  /**
+   * @param {string} data data
+   * @param {BufferEncoding=} encoding encoding
+   * @returns {void}
+   */
+  _updateWithShortString(data, encoding) {
+    const { exports, buffered, mem, chunkSize } = this;
+
+    let endPos;
+
+    if (data.length < 70) {
+      if (!encoding || encoding === 'utf-8' || encoding === 'utf8') {
+        endPos = buffered;
+        for (let i = 0; i < data.length; i++) {
+          const cc = data.charCodeAt(i);
+
+          if (cc < 0x80) {
+            mem[endPos++] = cc;
+          } else if (cc < 0x800) {
+            mem[endPos] = (cc >> 6) | 0xc0;
+            mem[endPos + 1] = (cc & 0x3f) | 0x80;
+            endPos += 2;
+          } else {
+            // bail-out for weird chars
+            endPos += mem.write(data.slice(i), endPos, encoding);
+            break;
+          }
+        }
+      } else if (encoding === 'latin1') {
+        endPos = buffered;
+
+        for (let i = 0; i < data.length; i++) {
+          const cc = data.charCodeAt(i);
+
+          mem[endPos++] = cc;
+        }
+      } else {
+        endPos = buffered + mem.write(data, buffered, encoding);
+      }
+    } else {
+      endPos = buffered + mem.write(data, buffered, encoding);
+    }
+
+    if (endPos < chunkSize) {
+      this.buffered = endPos;
+    } else {
+      const l = endPos & ~(this.chunkSize - 1);
+
+      exports.update(l);
+
+      const newBuffered = endPos - l;
+
+      this.buffered = newBuffered;
+
+      if (newBuffered > 0) {
+        mem.copyWithin(0, l, endPos);
+      }
+    }
+  }
+
+  /**
+   * @param {Buffer} data data
+   * @returns {void}
+   */
+  _updateWithBuffer(data) {
+    const { exports, buffered, mem } = this;
+    const length = data.length;
+
+    if (buffered + length < this.chunkSize) {
+      data.copy(mem, buffered, 0, length);
+
+      this.buffered += length;
+    } else {
+      const l = (buffered + length) & ~(this.chunkSize - 1);
+
+      if (l > 65536) {
+        let i = 65536 - buffered;
+
+        data.copy(mem, buffered, 0, i);
+        exports.update(65536);
+
+        const stop = l - buffered - 65536;
+
+        while (i < stop) {
+          data.copy(mem, 0, i, i + 65536);
+          exports.update(65536);
+          i += 65536;
+        }
+
+        data.copy(mem, 0, i, l - buffered);
+
+        exports.update(l - buffered - i);
+      } else {
+        data.copy(mem, buffered, 0, l - buffered);
+
+        exports.update(l);
+      }
+
+      const newBuffered = length + buffered - l;
+
+      this.buffered = newBuffered;
+
+      if (newBuffered > 0) {
+        data.copy(mem, 0, length - newBuffered, length);
+      }
+    }
+  }
+
+  digest(type) {
+    const { exports, buffered, mem, digestSize } = this;
+
+    exports.final(buffered);
+
+    this.instancesPool.push(this);
+
+    const hex = mem.toString('latin1', 0, digestSize);
+
+    if (type === 'hex') {
+      return hex;
+    }
+
+    if (type === 'binary' || !type) {
+      return Buffer.from(hex, 'hex');
+    }
+
+    return Buffer.from(hex, 'hex').toString(type);
+  }
+}
+
+const create = (wasmModule, instancesPool, chunkSize, digestSize) => {
+  if (instancesPool.length > 0) {
+    const old = instancesPool.pop();
+
+    old.reset();
+
+    return old;
+  } else {
+    return new WasmHash(
+      new WebAssembly.Instance(wasmModule),
+      instancesPool,
+      chunkSize,
+      digestSize
+    );
+  }
+};
+
+module.exports = create;
+module.exports.MAX_SHORT_STRING = MAX_SHORT_STRING;
Index: frontend/node_modules/loader-utils/lib/index.js
===================================================================
--- frontend/node_modules/loader-utils/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+'use strict';
+
+const getOptions = require('./getOptions');
+const parseQuery = require('./parseQuery');
+const stringifyRequest = require('./stringifyRequest');
+const getRemainingRequest = require('./getRemainingRequest');
+const getCurrentRequest = require('./getCurrentRequest');
+const isUrlRequest = require('./isUrlRequest');
+const urlToRequest = require('./urlToRequest');
+const parseString = require('./parseString');
+const getHashDigest = require('./getHashDigest');
+const interpolateName = require('./interpolateName');
+
+exports.getOptions = getOptions;
+exports.parseQuery = parseQuery;
+exports.stringifyRequest = stringifyRequest;
+exports.getRemainingRequest = getRemainingRequest;
+exports.getCurrentRequest = getCurrentRequest;
+exports.isUrlRequest = isUrlRequest;
+exports.urlToRequest = urlToRequest;
+exports.parseString = parseString;
+exports.getHashDigest = getHashDigest;
+exports.interpolateName = interpolateName;
Index: frontend/node_modules/loader-utils/lib/interpolateName.js
===================================================================
--- frontend/node_modules/loader-utils/lib/interpolateName.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/interpolateName.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,151 @@
+'use strict';
+
+const path = require('path');
+const emojisList = require('emojis-list');
+const getHashDigest = require('./getHashDigest');
+
+const emojiRegex = /[\uD800-\uDFFF]./;
+const emojiList = emojisList.filter((emoji) => emojiRegex.test(emoji));
+const emojiCache = {};
+
+function encodeStringToEmoji(content, length) {
+  if (emojiCache[content]) {
+    return emojiCache[content];
+  }
+
+  length = length || 1;
+
+  const emojis = [];
+
+  do {
+    if (!emojiList.length) {
+      throw new Error('Ran out of emoji');
+    }
+
+    const index = Math.floor(Math.random() * emojiList.length);
+
+    emojis.push(emojiList[index]);
+    emojiList.splice(index, 1);
+  } while (--length > 0);
+
+  const emojiEncoding = emojis.join('');
+
+  emojiCache[content] = emojiEncoding;
+
+  return emojiEncoding;
+}
+
+function interpolateName(loaderContext, name, options) {
+  let filename;
+
+  const hasQuery =
+    loaderContext.resourceQuery && loaderContext.resourceQuery.length > 1;
+
+  if (typeof name === 'function') {
+    filename = name(
+      loaderContext.resourcePath,
+      hasQuery ? loaderContext.resourceQuery : undefined
+    );
+  } else {
+    filename = name || '[hash].[ext]';
+  }
+
+  const context = options.context;
+  const content = options.content;
+  const regExp = options.regExp;
+
+  let ext = 'bin';
+  let basename = 'file';
+  let directory = '';
+  let folder = '';
+  let query = '';
+
+  if (loaderContext.resourcePath) {
+    const parsed = path.parse(loaderContext.resourcePath);
+    let resourcePath = loaderContext.resourcePath;
+
+    if (parsed.ext) {
+      ext = parsed.ext.substr(1);
+    }
+
+    if (parsed.dir) {
+      basename = parsed.name;
+      resourcePath = parsed.dir + path.sep;
+    }
+
+    if (typeof context !== 'undefined') {
+      directory = path
+        .relative(context, resourcePath + '_')
+        .replace(/\\/g, '/')
+        .replace(/\.\.(\/)?/g, '_$1');
+      directory = directory.substr(0, directory.length - 1);
+    } else {
+      directory = resourcePath.replace(/\\/g, '/').replace(/\.\.(\/)?/g, '_$1');
+    }
+
+    if (directory.length === 1) {
+      directory = '';
+    } else if (directory.length > 1) {
+      folder = path.basename(directory);
+    }
+  }
+
+  if (loaderContext.resourceQuery && loaderContext.resourceQuery.length > 1) {
+    query = loaderContext.resourceQuery;
+
+    const hashIdx = query.indexOf('#');
+
+    if (hashIdx >= 0) {
+      query = query.substr(0, hashIdx);
+    }
+  }
+
+  let url = filename;
+
+  if (content) {
+    // Match hash template
+    url = url
+      // `hash` and `contenthash` are same in `loader-utils` context
+      // let's keep `hash` for backward compatibility
+      .replace(
+        /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi,
+        (all, hashType, digestType, maxLength) =>
+          getHashDigest(content, hashType, digestType, parseInt(maxLength, 10))
+      )
+      .replace(/\[emoji(?::(\d+))?\]/gi, (all, length) =>
+        encodeStringToEmoji(content, parseInt(length, 10))
+      );
+  }
+
+  url = url
+    .replace(/\[ext\]/gi, () => ext)
+    .replace(/\[name\]/gi, () => basename)
+    .replace(/\[path\]/gi, () => directory)
+    .replace(/\[folder\]/gi, () => folder)
+    .replace(/\[query\]/gi, () => query);
+
+  if (regExp && loaderContext.resourcePath) {
+    const match = loaderContext.resourcePath.match(new RegExp(regExp));
+
+    match &&
+      match.forEach((matched, i) => {
+        url = url.replace(new RegExp('\\[' + i + '\\]', 'ig'), matched);
+      });
+  }
+
+  if (
+    typeof loaderContext.options === 'object' &&
+    typeof loaderContext.options.customInterpolateName === 'function'
+  ) {
+    url = loaderContext.options.customInterpolateName.call(
+      loaderContext,
+      url,
+      name,
+      options
+    );
+  }
+
+  return url;
+}
+
+module.exports = interpolateName;
Index: frontend/node_modules/loader-utils/lib/isUrlRequest.js
===================================================================
--- frontend/node_modules/loader-utils/lib/isUrlRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/isUrlRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+'use strict';
+
+const path = require('path');
+
+function isUrlRequest(url, root) {
+  // An URL is not an request if
+
+  // 1. It's an absolute url and it is not `windows` path like `C:\dir\file`
+  if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !path.win32.isAbsolute(url)) {
+    return false;
+  }
+
+  // 2. It's a protocol-relative
+  if (/^\/\//.test(url)) {
+    return false;
+  }
+
+  // 3. It's some kind of url for a template
+  if (/^[{}[\]#*;,'§$%&(=?`´^°<>]/.test(url)) {
+    return false;
+  }
+
+  // 4. It's also not an request if root isn't set and it's a root-relative url
+  if ((root === undefined || root === false) && /^\//.test(url)) {
+    return false;
+  }
+
+  return true;
+}
+
+module.exports = isUrlRequest;
Index: frontend/node_modules/loader-utils/lib/parseQuery.js
===================================================================
--- frontend/node_modules/loader-utils/lib/parseQuery.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/parseQuery.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,69 @@
+'use strict';
+
+const JSON5 = require('json5');
+
+const specialValues = {
+  null: null,
+  true: true,
+  false: false,
+};
+
+function parseQuery(query) {
+  if (query.substr(0, 1) !== '?') {
+    throw new Error(
+      "A valid query string passed to parseQuery should begin with '?'"
+    );
+  }
+
+  query = query.substr(1);
+
+  if (!query) {
+    return {};
+  }
+
+  if (query.substr(0, 1) === '{' && query.substr(-1) === '}') {
+    return JSON5.parse(query);
+  }
+
+  const queryArgs = query.split(/[,&]/g);
+  const result = Object.create(null);
+
+  queryArgs.forEach((arg) => {
+    const idx = arg.indexOf('=');
+
+    if (idx >= 0) {
+      let name = arg.substr(0, idx);
+      let value = decodeURIComponent(arg.substr(idx + 1));
+
+      // eslint-disable-next-line no-prototype-builtins
+      if (specialValues.hasOwnProperty(value)) {
+        value = specialValues[value];
+      }
+
+      if (name.substr(-2) === '[]') {
+        name = decodeURIComponent(name.substr(0, name.length - 2));
+
+        if (!Array.isArray(result[name])) {
+          result[name] = [];
+        }
+
+        result[name].push(value);
+      } else {
+        name = decodeURIComponent(name);
+        result[name] = value;
+      }
+    } else {
+      if (arg.substr(0, 1) === '-') {
+        result[decodeURIComponent(arg.substr(1))] = false;
+      } else if (arg.substr(0, 1) === '+') {
+        result[decodeURIComponent(arg.substr(1))] = true;
+      } else {
+        result[decodeURIComponent(arg)] = true;
+      }
+    }
+  });
+
+  return result;
+}
+
+module.exports = parseQuery;
Index: frontend/node_modules/loader-utils/lib/parseString.js
===================================================================
--- frontend/node_modules/loader-utils/lib/parseString.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/parseString.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+'use strict';
+
+function parseString(str) {
+  try {
+    if (str[0] === '"') {
+      return JSON.parse(str);
+    }
+
+    if (str[0] === "'" && str.substr(str.length - 1) === "'") {
+      return parseString(
+        str
+          .replace(/\\.|"/g, (x) => (x === '"' ? '\\"' : x))
+          .replace(/^'|'$/g, '"')
+      );
+    }
+
+    return JSON.parse('"' + str + '"');
+  } catch (e) {
+    return str;
+  }
+}
+
+module.exports = parseString;
Index: frontend/node_modules/loader-utils/lib/stringifyRequest.js
===================================================================
--- frontend/node_modules/loader-utils/lib/stringifyRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/stringifyRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+'use strict';
+
+const path = require('path');
+
+const matchRelativePath = /^\.\.?[/\\]/;
+
+function isAbsolutePath(str) {
+  return path.posix.isAbsolute(str) || path.win32.isAbsolute(str);
+}
+
+function isRelativePath(str) {
+  return matchRelativePath.test(str);
+}
+
+function stringifyRequest(loaderContext, request) {
+  const splitted = request.split('!');
+  const context =
+    loaderContext.context ||
+    (loaderContext.options && loaderContext.options.context);
+
+  return JSON.stringify(
+    splitted
+      .map((part) => {
+        // First, separate singlePath from query, because the query might contain paths again
+        const splittedPart = part.match(/^(.*?)(\?.*)/);
+        const query = splittedPart ? splittedPart[2] : '';
+        let singlePath = splittedPart ? splittedPart[1] : part;
+
+        if (isAbsolutePath(singlePath) && context) {
+          singlePath = path.relative(context, singlePath);
+
+          if (isAbsolutePath(singlePath)) {
+            // If singlePath still matches an absolute path, singlePath was on a different drive than context.
+            // In this case, we leave the path platform-specific without replacing any separators.
+            // @see https://github.com/webpack/loader-utils/pull/14
+            return singlePath + query;
+          }
+
+          if (isRelativePath(singlePath) === false) {
+            // Ensure that the relative path starts at least with ./ otherwise it would be a request into the modules directory (like node_modules).
+            singlePath = './' + singlePath;
+          }
+        }
+
+        return singlePath.replace(/\\/g, '/') + query;
+      })
+      .join('!')
+  );
+}
+
+module.exports = stringifyRequest;
Index: frontend/node_modules/loader-utils/lib/urlToRequest.js
===================================================================
--- frontend/node_modules/loader-utils/lib/urlToRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/lib/urlToRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,60 @@
+'use strict';
+
+// we can't use path.win32.isAbsolute because it also matches paths starting with a forward slash
+const matchNativeWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
+
+function urlToRequest(url, root) {
+  // Do not rewrite an empty url
+  if (url === '') {
+    return '';
+  }
+
+  const moduleRequestRegex = /^[^?]*~/;
+  let request;
+
+  if (matchNativeWin32Path.test(url)) {
+    // absolute windows path, keep it
+    request = url;
+  } else if (root !== undefined && root !== false && /^\//.test(url)) {
+    // if root is set and the url is root-relative
+    switch (typeof root) {
+      // 1. root is a string: root is prefixed to the url
+      case 'string':
+        // special case: `~` roots convert to module request
+        if (moduleRequestRegex.test(root)) {
+          request = root.replace(/([^~/])$/, '$1/') + url.slice(1);
+        } else {
+          request = root + url;
+        }
+        break;
+      // 2. root is `true`: absolute paths are allowed
+      //    *nix only, windows-style absolute paths are always allowed as they doesn't start with a `/`
+      case 'boolean':
+        request = url;
+        break;
+      default:
+        throw new Error(
+          "Unexpected parameters to loader-utils 'urlToRequest': url = " +
+            url +
+            ', root = ' +
+            root +
+            '.'
+        );
+    }
+  } else if (/^\.\.?\//.test(url)) {
+    // A relative url stays
+    request = url;
+  } else {
+    // every other url is threaded like a relative url
+    request = './' + url;
+  }
+
+  // A `~` makes the url an module
+  if (moduleRequestRegex.test(request)) {
+    request = request.replace(moduleRequestRegex, '');
+  }
+
+  return request;
+}
+
+module.exports = urlToRequest;
Index: frontend/node_modules/loader-utils/package.json
===================================================================
--- frontend/node_modules/loader-utils/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/loader-utils/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,39 @@
+{
+  "name": "loader-utils",
+  "version": "2.0.4",
+  "author": "Tobias Koppers @sokra",
+  "description": "utils for webpack loaders",
+  "dependencies": {
+    "big.js": "^5.2.2",
+    "emojis-list": "^3.0.0",
+    "json5": "^2.1.2"
+  },
+  "scripts": {
+    "lint": "eslint lib test",
+    "pretest": "yarn lint",
+    "test": "jest",
+    "test:ci": "jest --coverage",
+    "release": "yarn test && standard-version"
+  },
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/webpack/loader-utils.git"
+  },
+  "engines": {
+    "node": ">=8.9.0"
+  },
+  "devDependencies": {
+    "coveralls": "^3.0.9",
+    "eslint": "^6.8.0",
+    "eslint-plugin-node": "^11.0.0",
+    "eslint-plugin-prettier": "^3.1.2",
+    "jest": "^25.1.0",
+    "prettier": "^1.19.1",
+    "standard-version": "^7.1.0"
+  },
+  "main": "lib/index.js",
+  "files": [
+    "lib"
+  ]
+}
