Index: frontend/node_modules/react-dev-utils/FileSizeReporter.js
===================================================================
--- frontend/node_modules/react-dev-utils/FileSizeReporter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/FileSizeReporter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+var chalk = require('chalk');
+var filesize = require('filesize');
+var recursive = require('recursive-readdir');
+var stripAnsi = require('strip-ansi');
+var gzipSize = require('gzip-size').sync;
+
+function canReadAsset(asset) {
+  return (
+    /\.(js|css)$/.test(asset) &&
+    !/service-worker\.js/.test(asset) &&
+    !/precache-manifest\.[0-9a-f]+\.js/.test(asset)
+  );
+}
+
+// Prints a detailed summary of build files.
+function printFileSizesAfterBuild(
+  webpackStats,
+  previousSizeMap,
+  buildFolder,
+  maxBundleGzipSize,
+  maxChunkGzipSize
+) {
+  var root = previousSizeMap.root;
+  var sizes = previousSizeMap.sizes;
+  var assets = (webpackStats.stats || [webpackStats])
+    .map(stats =>
+      stats
+        .toJson({ all: false, assets: true })
+        .assets.filter(asset => canReadAsset(asset.name))
+        .map(asset => {
+          var fileContents = fs.readFileSync(path.join(root, asset.name));
+          var size = gzipSize(fileContents);
+          var previousSize = sizes[removeFileNameHash(root, asset.name)];
+          var difference = getDifferenceLabel(size, previousSize);
+          return {
+            folder: path.join(
+              path.basename(buildFolder),
+              path.dirname(asset.name)
+            ),
+            name: path.basename(asset.name),
+            size: size,
+            sizeLabel:
+              filesize(size) + (difference ? ' (' + difference + ')' : ''),
+          };
+        })
+    )
+    .reduce((single, all) => all.concat(single), []);
+  assets.sort((a, b) => b.size - a.size);
+  var longestSizeLabelLength = Math.max.apply(
+    null,
+    assets.map(a => stripAnsi(a.sizeLabel).length)
+  );
+  var suggestBundleSplitting = false;
+  assets.forEach(asset => {
+    var sizeLabel = asset.sizeLabel;
+    var sizeLength = stripAnsi(sizeLabel).length;
+    if (sizeLength < longestSizeLabelLength) {
+      var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
+      sizeLabel += rightPadding;
+    }
+    var isMainBundle = asset.name.indexOf('main.') === 0;
+    var maxRecommendedSize = isMainBundle
+      ? maxBundleGzipSize
+      : maxChunkGzipSize;
+    var isLarge = maxRecommendedSize && asset.size > maxRecommendedSize;
+    if (isLarge && path.extname(asset.name) === '.js') {
+      suggestBundleSplitting = true;
+    }
+    console.log(
+      '  ' +
+        (isLarge ? chalk.yellow(sizeLabel) : sizeLabel) +
+        '  ' +
+        chalk.dim(asset.folder + path.sep) +
+        chalk.cyan(asset.name)
+    );
+  });
+  if (suggestBundleSplitting) {
+    console.log();
+    console.log(
+      chalk.yellow('The bundle size is significantly larger than recommended.')
+    );
+    console.log(
+      chalk.yellow(
+        'Consider reducing it with code splitting: https://goo.gl/9VhYWB'
+      )
+    );
+    console.log(
+      chalk.yellow(
+        'You can also analyze the project dependencies: https://goo.gl/LeUzfb'
+      )
+    );
+  }
+}
+
+function removeFileNameHash(buildFolder, fileName) {
+  return fileName
+    .replace(buildFolder, '')
+    .replace(/\\/g, '/')
+    .replace(
+      /\/?(.*)(\.[0-9a-f]+)(\.chunk)?(\.js|\.css)/,
+      (match, p1, p2, p3, p4) => p1 + p4
+    );
+}
+
+// Input: 1024, 2048
+// Output: "(+1 KB)"
+function getDifferenceLabel(currentSize, previousSize) {
+  var FIFTY_KILOBYTES = 1024 * 50;
+  var difference = currentSize - previousSize;
+  var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
+  if (difference >= FIFTY_KILOBYTES) {
+    return chalk.red('+' + fileSize);
+  } else if (difference < FIFTY_KILOBYTES && difference > 0) {
+    return chalk.yellow('+' + fileSize);
+  } else if (difference < 0) {
+    return chalk.green(fileSize);
+  } else {
+    return '';
+  }
+}
+
+function measureFileSizesBeforeBuild(buildFolder) {
+  return new Promise(resolve => {
+    recursive(buildFolder, (err, fileNames) => {
+      var sizes;
+      if (!err && fileNames) {
+        sizes = fileNames.filter(canReadAsset).reduce((memo, fileName) => {
+          var contents = fs.readFileSync(fileName);
+          var key = removeFileNameHash(buildFolder, fileName);
+          memo[key] = gzipSize(contents);
+          return memo;
+        }, {});
+      }
+      resolve({
+        root: buildFolder,
+        sizes: sizes || {},
+      });
+    });
+  });
+}
+
+module.exports = {
+  measureFileSizesBeforeBuild: measureFileSizesBeforeBuild,
+  printFileSizesAfterBuild: printFileSizesAfterBuild,
+};
Index: frontend/node_modules/react-dev-utils/ForkTsCheckerWarningWebpackPlugin.js
===================================================================
--- frontend/node_modules/react-dev-utils/ForkTsCheckerWarningWebpackPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/ForkTsCheckerWarningWebpackPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+// References:
+// - https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#plugin-hooks
+// - https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/issues/232#issuecomment-645543747
+const ForkTsCheckerWebpackPlugin = require('./ForkTsCheckerWebpackPlugin');
+
+module.exports = class ForkTsCheckerWarningWebpackPlugin {
+  apply(compiler) {
+    new ForkTsCheckerWebpackPlugin().apply(compiler);
+
+    const hooks = ForkTsCheckerWebpackPlugin.getCompilerHooks(compiler);
+
+    hooks.issues.tap('ForkTsCheckerWarningWebpackPlugin', issues =>
+      issues.map(issue => ({ ...issue, severity: 'warning' }))
+    );
+  }
+};
Index: frontend/node_modules/react-dev-utils/ForkTsCheckerWebpackPlugin.js
===================================================================
--- frontend/node_modules/react-dev-utils/ForkTsCheckerWebpackPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/ForkTsCheckerWebpackPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
+
+module.exports = ForkTsCheckerWebpackPlugin;
Index: frontend/node_modules/react-dev-utils/InlineChunkHtmlPlugin.js
===================================================================
--- frontend/node_modules/react-dev-utils/InlineChunkHtmlPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/InlineChunkHtmlPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+class InlineChunkHtmlPlugin {
+  constructor(htmlWebpackPlugin, tests) {
+    this.htmlWebpackPlugin = htmlWebpackPlugin;
+    this.tests = tests;
+  }
+
+  getInlinedTag(publicPath, assets, tag) {
+    if (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) {
+      return tag;
+    }
+    const scriptName = publicPath
+      ? tag.attributes.src.replace(publicPath, '')
+      : tag.attributes.src;
+    if (!this.tests.some(test => scriptName.match(test))) {
+      return tag;
+    }
+    const asset = assets[scriptName];
+    if (asset == null) {
+      return tag;
+    }
+    return { tagName: 'script', innerHTML: asset.source(), closeTag: true };
+  }
+
+  apply(compiler) {
+    let publicPath = compiler.options.output.publicPath || '';
+    if (publicPath && !publicPath.endsWith('/')) {
+      publicPath += '/';
+    }
+
+    compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', compilation => {
+      const tagFunction = tag =>
+        this.getInlinedTag(publicPath, compilation.assets, tag);
+
+      const hooks = this.htmlWebpackPlugin.getHooks(compilation);
+      hooks.alterAssetTagGroups.tap('InlineChunkHtmlPlugin', assets => {
+        assets.headTags = assets.headTags.map(tagFunction);
+        assets.bodyTags = assets.bodyTags.map(tagFunction);
+      });
+
+      // Still emit the runtime chunk for users who do not use our generated
+      // index.html file.
+      // hooks.afterEmit.tap('InlineChunkHtmlPlugin', () => {
+      //   Object.keys(compilation.assets).forEach(assetName => {
+      //     if (this.tests.some(test => assetName.match(test))) {
+      //       delete compilation.assets[assetName];
+      //     }
+      //   });
+      // });
+    });
+  }
+}
+
+module.exports = InlineChunkHtmlPlugin;
Index: frontend/node_modules/react-dev-utils/InterpolateHtmlPlugin.js
===================================================================
--- frontend/node_modules/react-dev-utils/InterpolateHtmlPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/InterpolateHtmlPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// This webpack plugin lets us interpolate custom variables into `index.html`.
+// Usage: `new InterpolateHtmlPlugin(HtmlWebpackPlugin, { 'MY_VARIABLE': 42 })`
+// Then, you can use %MY_VARIABLE% in your `index.html`.
+
+// It works in tandem with HtmlWebpackPlugin.
+// Learn more about creating plugins like this:
+// https://github.com/ampedandwired/html-webpack-plugin#events
+
+'use strict';
+const escapeStringRegexp = require('escape-string-regexp');
+
+class InterpolateHtmlPlugin {
+  constructor(htmlWebpackPlugin, replacements) {
+    this.htmlWebpackPlugin = htmlWebpackPlugin;
+    this.replacements = replacements;
+  }
+
+  apply(compiler) {
+    compiler.hooks.compilation.tap('InterpolateHtmlPlugin', compilation => {
+      this.htmlWebpackPlugin
+        .getHooks(compilation)
+        .afterTemplateExecution.tap('InterpolateHtmlPlugin', data => {
+          // Run HTML through a series of user-specified string replacements.
+          Object.keys(this.replacements).forEach(key => {
+            const value = this.replacements[key];
+            data.html = data.html.replace(
+              new RegExp('%' + escapeStringRegexp(key) + '%', 'g'),
+              value
+            );
+          });
+        });
+    });
+  }
+}
+
+module.exports = InterpolateHtmlPlugin;
Index: frontend/node_modules/react-dev-utils/LICENSE
===================================================================
--- frontend/node_modules/react-dev-utils/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2013-present, Facebook, Inc.
+
+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/react-dev-utils/ModuleNotFoundPlugin.js
===================================================================
--- frontend/node_modules/react-dev-utils/ModuleNotFoundPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/ModuleNotFoundPlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const chalk = require('chalk');
+const findUp = require('find-up');
+const path = require('path');
+
+class ModuleNotFoundPlugin {
+  constructor(appPath, yarnLockFile) {
+    this.appPath = appPath;
+    this.yarnLockFile = yarnLockFile;
+
+    this.useYarnCommand = this.useYarnCommand.bind(this);
+    this.getRelativePath = this.getRelativePath.bind(this);
+    this.prettierError = this.prettierError.bind(this);
+  }
+
+  useYarnCommand() {
+    try {
+      return findUp.sync('yarn.lock', { cwd: this.appPath }) != null;
+    } catch (_) {
+      return false;
+    }
+  }
+
+  getRelativePath(_file) {
+    let file = path.relative(this.appPath, _file);
+    if (file.startsWith('..')) {
+      file = _file;
+    } else if (!file.startsWith('.')) {
+      file = '.' + path.sep + file;
+    }
+    return file;
+  }
+
+  prettierError(err) {
+    let { details: _details = '', origin } = err;
+
+    if (origin == null) {
+      const caseSensitivity =
+        err.message &&
+        /\[CaseSensitivePathsPlugin\] `(.*?)` .* `(.*?)`/.exec(err.message);
+      if (caseSensitivity) {
+        const [, incorrectPath, actualName] = caseSensitivity;
+        const actualFile = this.getRelativePath(
+          path.join(path.dirname(incorrectPath), actualName)
+        );
+        const incorrectName = path.basename(incorrectPath);
+        err.message = `Cannot find file: '${incorrectName}' does not match the corresponding name on disk: '${actualFile}'.`;
+      }
+      return err;
+    }
+
+    const file = this.getRelativePath(origin.resource);
+    let details = _details.split('\n');
+
+    const request = /resolve '(.*?)' in '(.*?)'/.exec(details);
+    if (request) {
+      const isModule = details[1] && details[1].includes('module');
+      const isFile = details[1] && details[1].includes('file');
+
+      let [, target, context] = request;
+      context = this.getRelativePath(context);
+      if (isModule) {
+        const isYarn = this.useYarnCommand();
+        details = [
+          `Cannot find module: '${target}'. Make sure this package is installed.`,
+          '',
+          'You can install this package by running: ' +
+            (isYarn
+              ? chalk.bold(`yarn add ${target}`)
+              : chalk.bold(`npm install ${target}`)) +
+            '.',
+        ];
+      } else if (isFile) {
+        details = [`Cannot find file '${target}' in '${context}'.`];
+      } else {
+        details = [err.message];
+      }
+    } else {
+      details = [err.message];
+    }
+    err.message = [file, ...details].join('\n').replace('Error: ', '');
+
+    const isModuleScopePluginError =
+      err.error && err.error.__module_scope_plugin;
+    if (isModuleScopePluginError) {
+      err.message = err.message.replace('Module not found: ', '');
+    }
+    return err;
+  }
+
+  apply(compiler) {
+    const { prettierError } = this;
+    compiler.hooks.make.intercept({
+      register(tap) {
+        if (!(tap.name === 'MultiEntryPlugin' || tap.name === 'EntryPlugin')) {
+          return tap;
+        }
+        return Object.assign({}, tap, {
+          fn: (compilation, callback) => {
+            tap.fn(compilation, (err, ...args) => {
+              if (err && err.name === 'ModuleNotFoundError') {
+                err = prettierError(err);
+              }
+              callback(err, ...args);
+            });
+          },
+        });
+      },
+    });
+    compiler.hooks.normalModuleFactory.tap('ModuleNotFoundPlugin', nmf => {
+      nmf.hooks.afterResolve.intercept({
+        register(tap) {
+          if (tap.name !== 'CaseSensitivePathsPlugin') {
+            return tap;
+          }
+          return Object.assign({}, tap, {
+            fn: (compilation, callback) => {
+              tap.fn(compilation, (err, ...args) => {
+                if (
+                  err &&
+                  err.message &&
+                  err.message.includes('CaseSensitivePathsPlugin')
+                ) {
+                  err = prettierError(err);
+                }
+                callback(err, ...args);
+              });
+            },
+          });
+        },
+      });
+    });
+  }
+}
+
+module.exports = ModuleNotFoundPlugin;
Index: frontend/node_modules/react-dev-utils/ModuleScopePlugin.js
===================================================================
--- frontend/node_modules/react-dev-utils/ModuleScopePlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/ModuleScopePlugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const chalk = require('chalk');
+const path = require('path');
+const os = require('os');
+
+class ModuleScopePlugin {
+  constructor(appSrc, allowedFiles = []) {
+    this.appSrcs = Array.isArray(appSrc) ? appSrc : [appSrc];
+    this.allowedFiles = new Set(allowedFiles);
+    this.allowedPaths = [...allowedFiles].map(path.dirname).filter(p => path.relative(p, process.cwd()) !== '');
+  }
+
+  apply(resolver) {
+    const { appSrcs } = this;
+    resolver.hooks.file.tapAsync(
+      'ModuleScopePlugin',
+      (request, contextResolver, callback) => {
+        // Unknown issuer, probably webpack internals
+        if (!request.context.issuer) {
+          return callback();
+        }
+        if (
+          // If this resolves to a node_module, we don't care what happens next
+          request.descriptionFileRoot.indexOf('/node_modules/') !== -1 ||
+          request.descriptionFileRoot.indexOf('\\node_modules\\') !== -1 ||
+          // Make sure this request was manual
+          !request.__innerRequest_request
+        ) {
+          return callback();
+        }
+        // Resolve the issuer from our appSrc and make sure it's one of our files
+        // Maybe an indexOf === 0 would be better?
+        if (
+          appSrcs.every(appSrc => {
+            const relative = path.relative(appSrc, request.context.issuer);
+            // If it's not in one of our app src or a subdirectory, not our request!
+            return relative.startsWith('../') || relative.startsWith('..\\');
+          })
+        ) {
+          return callback();
+        }
+        const requestFullPath = path.resolve(
+          path.dirname(request.context.issuer),
+          request.__innerRequest_request
+        );
+        if (this.allowedFiles.has(requestFullPath)) {
+          return callback();
+        }
+        if (this.allowedPaths.some((allowedFile) => {
+          return requestFullPath.startsWith(allowedFile);
+        })) {
+          return callback();
+        }
+        // Find path from src to the requested file
+        // Error if in a parent directory of all given appSrcs
+        if (
+          appSrcs.every(appSrc => {
+            const requestRelative = path.relative(appSrc, requestFullPath);
+            return (
+              requestRelative.startsWith('../') ||
+              requestRelative.startsWith('..\\')
+            );
+          })
+        ) {
+          const scopeError = new Error(
+            `You attempted to import ${chalk.cyan(
+              request.__innerRequest_request
+            )} which falls outside of the project ${chalk.cyan(
+              'src/'
+            )} directory. ` +
+              `Relative imports outside of ${chalk.cyan(
+                'src/'
+              )} are not supported.` +
+              os.EOL +
+              `You can either move it inside ${chalk.cyan(
+                'src/'
+              )}, or add a symlink to it from project's ${chalk.cyan(
+                'node_modules/'
+              )}.`
+          );
+          Object.defineProperty(scopeError, '__module_scope_plugin', {
+            value: true,
+            writable: false,
+            enumerable: false,
+          });
+          callback(scopeError, request);
+        } else {
+          callback();
+        }
+      }
+    );
+  }
+}
+
+module.exports = ModuleScopePlugin;
Index: frontend/node_modules/react-dev-utils/README.md
===================================================================
--- frontend/node_modules/react-dev-utils/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,396 @@
+# react-dev-utils
+
+This package includes some utilities used by [Create React App](https://github.com/facebook/create-react-app).<br>
+Please refer to its documentation:
+
+- [Getting Started](https://facebook.github.io/create-react-app/docs/getting-started) – How to create a new app.
+- [User Guide](https://facebook.github.io/create-react-app/) – How to develop apps bootstrapped with Create React App.
+
+## Usage in Create React App Projects
+
+These utilities come by default with [Create React App](https://github.com/facebook/create-react-app). **You don’t need to install it separately in Create React App projects.**
+
+## Usage Outside of Create React App
+
+If you don’t use Create React App, or if you [ejected](https://facebook.github.io/create-react-app/docs/available-scripts#npm-run-eject), you may keep using these utilities. Their development will be aligned with Create React App, so major versions of these utilities may come out relatively often. Feel free to fork or copy and paste them into your projects if you’d like to have more control over them, or feel free to use the old versions. Not all of them are React-specific, but we might make some of them more React-specific in the future.
+
+### Entry Points
+
+There is no single entry point. You can only import individual top-level modules.
+
+#### `new InterpolateHtmlPlugin(htmlWebpackPlugin: HtmlWebpackPlugin, replacements: {[key:string]: string})`
+
+This webpack plugin lets us interpolate custom variables into `index.html`.<br>
+It works in tandem with [HtmlWebpackPlugin](https://github.com/ampedandwired/html-webpack-plugin) 2.x via its [events](https://github.com/ampedandwired/html-webpack-plugin#events).
+
+```js
+var path = require('path');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
+
+// webpack config
+var publicUrl = '/my-custom-url';
+
+module.exports = {
+  output: {
+    // ...
+    publicPath: publicUrl + '/',
+  },
+  // ...
+  plugins: [
+    // Generates an `index.html` file with the <script> injected.
+    new HtmlWebpackPlugin({
+      inject: true,
+      template: path.resolve('public/index.html'),
+    }),
+    // Makes the public URL available as %PUBLIC_URL% in index.html, e.g.:
+    // <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
+    new InterpolateHtmlPlugin(HtmlWebpackPlugin, {
+      PUBLIC_URL: publicUrl,
+      // You can pass any key-value pairs, this was just an example.
+      // WHATEVER: 42 will replace %WHATEVER% with 42 in index.html.
+    }),
+    // ...
+  ],
+  // ...
+};
+```
+
+#### `new InlineChunkHtmlPlugin(htmlWebpackPlugin: HtmlWebpackPlugin, tests: Regex[])`
+
+This webpack plugin inlines script chunks into `index.html`.<br>
+It works in tandem with [HtmlWebpackPlugin](https://github.com/ampedandwired/html-webpack-plugin) 4.x.
+
+```js
+var path = require('path');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
+
+// webpack config
+var publicUrl = '/my-custom-url';
+
+module.exports = {
+  output: {
+    // ...
+    publicPath: publicUrl + '/',
+  },
+  // ...
+  plugins: [
+    // Generates an `index.html` file with the <script> injected.
+    new HtmlWebpackPlugin({
+      inject: true,
+      template: path.resolve('public/index.html'),
+    }),
+    // Inlines chunks with `runtime` in the name
+    new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime/]),
+    // ...
+  ],
+  // ...
+};
+```
+
+#### `new ModuleScopePlugin(appSrc: string | string[], allowedFiles?: string[])`
+
+This webpack plugin ensures that relative imports from app's source directories don't reach outside of it.
+
+```js
+var path = require('path');
+var ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
+
+module.exports = {
+  // ...
+  resolve: {
+    // ...
+    plugins: [
+      new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
+      // ...
+    ],
+    // ...
+  },
+  // ...
+};
+```
+
+#### `checkRequiredFiles(files: Array<string>): boolean`
+
+Makes sure that all passed files exist.<br>
+Filenames are expected to be absolute.<br>
+If a file is not found, prints a warning message and returns `false`.
+
+```js
+var path = require('path');
+var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
+
+if (
+  !checkRequiredFiles([
+    path.resolve('public/index.html'),
+    path.resolve('src/index.js'),
+  ])
+) {
+  process.exit(1);
+}
+```
+
+#### `clearConsole(): void`
+
+Clears the console, hopefully in a cross-platform way.
+
+```js
+var clearConsole = require('react-dev-utils/clearConsole');
+
+clearConsole();
+console.log('Just cleared the screen!');
+```
+
+#### `eslintFormatter(results: Object): string`
+
+This is our custom ESLint formatter that integrates well with Create React App console output.<br>
+You can use the default one instead if you prefer so.
+
+```js
+const eslintFormatter = require('react-dev-utils/eslintFormatter');
+
+// In your webpack config:
+// ...
+module: {
+  rules: [
+    {
+      test: /\.(js|jsx)$/,
+      include: paths.appSrc,
+      enforce: 'pre',
+      use: [
+        {
+          loader: 'eslint-loader',
+          options: {
+            // Pass the formatter:
+            formatter: eslintFormatter,
+          },
+        },
+      ],
+    },
+  ];
+}
+```
+
+#### `FileSizeReporter`
+
+##### `measureFileSizesBeforeBuild(buildFolder: string): Promise<OpaqueFileSizes>`
+
+Captures JS and CSS asset sizes inside the passed `buildFolder`. Save the result value to compare it after the build.
+
+##### `printFileSizesAfterBuild(webpackStats: WebpackStats, previousFileSizes: OpaqueFileSizes, buildFolder: string, maxBundleGzipSize?: number, maxChunkGzipSize?: number)`
+
+Prints the JS and CSS asset sizes after the build, and includes a size comparison with `previousFileSizes` that were captured earlier using `measureFileSizesBeforeBuild()`. `maxBundleGzipSize` and `maxChunkGzipSizemay` may optionally be specified to display a warning when the main bundle or a chunk exceeds the specified size (in bytes).
+
+```js
+var {
+  measureFileSizesBeforeBuild,
+  printFileSizesAfterBuild,
+} = require('react-dev-utils/FileSizeReporter');
+
+measureFileSizesBeforeBuild(buildFolder).then(previousFileSizes => {
+  return cleanAndRebuild().then(webpackStats => {
+    printFileSizesAfterBuild(webpackStats, previousFileSizes, buildFolder);
+  });
+});
+```
+
+#### `formatWebpackMessages({errors: Array<string>, warnings: Array<string>}): {errors: Array<string>, warnings: Array<string>}`
+
+Extracts and prettifies warning and error messages from webpack [stats](https://github.com/webpack/docs/wiki/node.js-api#stats) object.
+
+```js
+var webpack = require('webpack');
+var config = require('../config/webpack.config.dev');
+var formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
+
+var compiler = webpack(config);
+
+compiler.hooks.invalid.tap('invalid', function () {
+  console.log('Compiling...');
+});
+
+compiler.hooks.done.tap('done', function (stats) {
+  var rawMessages = stats.toJson({}, true);
+  var messages = formatWebpackMessages(rawMessages);
+  if (!messages.errors.length && !messages.warnings.length) {
+    console.log('Compiled successfully!');
+  }
+  if (messages.errors.length) {
+    console.log('Failed to compile.');
+    messages.errors.forEach(e => console.log(e));
+    return;
+  }
+  if (messages.warnings.length) {
+    console.log('Compiled with warnings.');
+    messages.warnings.forEach(w => console.log(w));
+  }
+});
+```
+
+#### `printBuildError(error: Object): void`
+
+Prettify some known build errors.
+Pass an Error object to log a prettified error message in the console.
+
+```
+  const printBuildError = require('react-dev-utils/printBuildError')
+  try {
+    build()
+  } catch(e) {
+    printBuildError(e) // logs prettified message
+  }
+```
+
+#### `getProcessForPort(port: number): string`
+
+Finds the currently running process on `port`.
+Returns a string containing the name and directory, e.g.,
+
+```
+create-react-app
+in /Users/developer/create-react-app
+```
+
+```js
+var getProcessForPort = require('react-dev-utils/getProcessForPort');
+
+getProcessForPort(3000);
+```
+
+#### `launchEditor(fileName: string, lineNumber: number): void`
+
+On macOS, tries to find a known running editor process and opens the file in it. It can also be explicitly configured by `REACT_EDITOR`, `VISUAL`, or `EDITOR` environment variables. For example, you can put `REACT_EDITOR=atom` in your `.env.local` file, and Create React App will respect that.
+
+#### `noopServiceWorkerMiddleware(servedPath: string): ExpressMiddleware`
+
+Returns Express middleware that serves a `${servedPath}/service-worker.js` that resets any previously set service worker configuration. Useful for development.
+
+#### `redirectServedPathMiddleware(servedPath: string): ExpressMiddleware`
+
+Returns Express middleware that redirects to `${servedPath}/${req.path}`, if `req.url`
+does not start with `servedPath`. Useful for development.
+
+#### `openBrowser(url: string): boolean`
+
+Attempts to open the browser with a given URL.<br>
+On Mac OS X, attempts to reuse an existing Chrome tab via AppleScript.<br>
+Otherwise, falls back to [opn](https://github.com/sindresorhus/opn) behavior.
+
+```js
+var path = require('path');
+var openBrowser = require('react-dev-utils/openBrowser');
+
+if (openBrowser('http://localhost:3000')) {
+  console.log('The browser tab has been opened!');
+}
+```
+
+#### `printHostingInstructions(appPackage: Object, publicUrl: string, publicPath: string, buildFolder: string, useYarn: boolean): void`
+
+Prints hosting instructions after the project is built.
+
+Pass your parsed `package.json` object as `appPackage`, your URL where you plan to host the app as `publicUrl`, `output.publicPath` from your webpack configuration as `publicPath`, the `buildFolder` name, and whether to `useYarn` in instructions.
+
+```js
+const appPackage = require(paths.appPackageJson);
+const publicUrl = paths.publicUrlOrPath;
+const publicPath = config.output.publicPath;
+printHostingInstructions(appPackage, publicUrl, publicPath, 'build', true);
+```
+
+#### `WebpackDevServerUtils`
+
+##### `choosePort(host: string, defaultPort: number): Promise<number | null>`
+
+Returns a Promise resolving to either `defaultPort` or next available port if the user confirms it is okay to do. If the port is taken and the user has refused to use another port, or if the terminal is not interactive and can’t present user with the choice, resolves to `null`.
+
+##### `createCompiler(args: Object): WebpackCompiler`
+
+Creates a webpack compiler instance for WebpackDevServer with built-in helpful messages.
+
+The `args` object accepts a number of properties:
+
+- **appName** `string`: The name that will be printed to the terminal.
+- **config** `Object`: The webpack configuration options to be provided to the webpack constructor.
+- **urls** `Object`: To provide the `urls` argument, use `prepareUrls()` described below.
+- **useYarn** `boolean`: If `true`, yarn instructions will be emitted in the terminal instead of npm.
+- **useTypeScript** `boolean`: If `true`, TypeScript type checking will be enabled. Be sure to provide the `devSocket` argument above if this is set to `true`.
+- **webpack** `function`: A reference to the webpack constructor.
+
+##### `prepareProxy(proxySetting: string, appPublicFolder: string, servedPathname: string): Object`
+
+Creates a WebpackDevServer `proxy` configuration object from the `proxy` setting in `package.json`.
+
+##### `prepareUrls(protocol: string, host: string, port: number, pathname: string = '/'): Object`
+
+Returns an object with local and remote URLs for the development server. Pass this object to `createCompiler()` described above.
+
+#### `webpackHotDevClient`
+
+This is an alternative client for [WebpackDevServer](https://github.com/webpack/webpack-dev-server) that shows a syntax error overlay.
+
+It currently supports only webpack 3.x.
+
+```js
+// webpack development config
+module.exports = {
+  // ...
+  entry: [
+    // You can replace the line below with these two lines if you prefer the
+    // stock client:
+    // require.resolve('webpack-dev-server/client') + '?/',
+    // require.resolve('webpack/hot/dev-server'),
+    'react-dev-utils/webpackHotDevClient',
+    'src/index',
+  ],
+  // ...
+};
+```
+
+#### `getCSSModuleLocalIdent(context: Object, localIdentName: String, localName: String, options: Object): string`
+
+Creates a class name for CSS Modules that uses either the filename or folder name if named `index.module.css`.
+
+For `MyFolder/MyComponent.module.css` and class `MyClass` the output will be `MyComponent.module_MyClass__[hash]`
+For `MyFolder/index.module.css` and class `MyClass` the output will be `MyFolder_MyClass__[hash]`
+
+```js
+const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
+
+// In your webpack config:
+// ...
+module: {
+  rules: [
+    {
+      test: /\.module\.css$/,
+      use: [
+        require.resolve('style-loader'),
+        {
+          loader: require.resolve('css-loader'),
+          options: {
+            importLoaders: 1,
+            modules: {
+              getLocalIdent: getCSSModuleLocalIdent,
+            },
+          },
+        },
+        {
+          loader: require.resolve('postcss-loader'),
+          options: postCSSLoaderOptions,
+        },
+      ],
+    },
+  ];
+}
+```
+
+#### `getCacheIdentifier(environment: string, packages: string[]): string`
+
+Returns a cache identifier (string) consisting of the specified environment and related package versions, e.g.,
+
+```js
+var getCacheIdentifier = require('react-dev-utils/getCacheIdentifier');
+
+getCacheIdentifier('prod', ['react-dev-utils', 'chalk']); // # => 'prod:react-dev-utils@5.0.0:chalk@3.0.0'
+```
Index: frontend/node_modules/react-dev-utils/WebpackDevServerUtils.js
===================================================================
--- frontend/node_modules/react-dev-utils/WebpackDevServerUtils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/WebpackDevServerUtils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,443 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+const address = require('address');
+const fs = require('fs');
+const path = require('path');
+const url = require('url');
+const chalk = require('chalk');
+const detect = require('detect-port-alt');
+const isRoot = require('is-root');
+const prompts = require('prompts');
+const clearConsole = require('./clearConsole');
+const formatWebpackMessages = require('./formatWebpackMessages');
+const getProcessForPort = require('./getProcessForPort');
+const forkTsCheckerWebpackPlugin = require('./ForkTsCheckerWebpackPlugin');
+
+const isInteractive = process.stdout.isTTY;
+
+function prepareUrls(protocol, host, port, pathname = '/') {
+  const formatUrl = hostname =>
+    url.format({
+      protocol,
+      hostname,
+      port,
+      pathname,
+    });
+  const prettyPrintUrl = hostname =>
+    url.format({
+      protocol,
+      hostname,
+      port: chalk.bold(port),
+      pathname,
+    });
+
+  const isUnspecifiedHost = host === '0.0.0.0' || host === '::';
+  let prettyHost, lanUrlForConfig, lanUrlForTerminal;
+  if (isUnspecifiedHost) {
+    prettyHost = 'localhost';
+    try {
+      // This can only return an IPv4 address
+      lanUrlForConfig = address.ip();
+      if (lanUrlForConfig) {
+        // Check if the address is a private ip
+        // https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
+        if (
+          /^10[.]|^172[.](1[6-9]|2[0-9]|3[0-1])[.]|^192[.]168[.]/.test(
+            lanUrlForConfig
+          )
+        ) {
+          // Address is private, format it for later use
+          lanUrlForTerminal = prettyPrintUrl(lanUrlForConfig);
+        } else {
+          // Address is not private, so we will discard it
+          lanUrlForConfig = undefined;
+        }
+      }
+    } catch (_e) {
+      // ignored
+    }
+  } else {
+    prettyHost = host;
+  }
+  const localUrlForTerminal = prettyPrintUrl(prettyHost);
+  const localUrlForBrowser = formatUrl(prettyHost);
+  return {
+    lanUrlForConfig,
+    lanUrlForTerminal,
+    localUrlForTerminal,
+    localUrlForBrowser,
+  };
+}
+
+function printInstructions(appName, urls, useYarn) {
+  console.log();
+  console.log(`You can now view ${chalk.bold(appName)} in the browser.`);
+  console.log();
+
+  if (urls.lanUrlForTerminal) {
+    console.log(
+      `  ${chalk.bold('Local:')}            ${urls.localUrlForTerminal}`
+    );
+    console.log(
+      `  ${chalk.bold('On Your Network:')}  ${urls.lanUrlForTerminal}`
+    );
+  } else {
+    console.log(`  ${urls.localUrlForTerminal}`);
+  }
+
+  console.log();
+  console.log('Note that the development build is not optimized.');
+  console.log(
+    `To create a production build, use ` +
+      `${chalk.cyan(`${useYarn ? 'yarn' : 'npm run'} build`)}.`
+  );
+  console.log();
+}
+
+function createCompiler({
+  appName,
+  config,
+  urls,
+  useYarn,
+  useTypeScript,
+  webpack,
+}) {
+  // "Compiler" is a low-level interface to webpack.
+  // It lets us listen to some events and provide our own custom messages.
+  let compiler;
+  try {
+    compiler = webpack(config);
+  } catch (err) {
+    console.log(chalk.red('Failed to compile.'));
+    console.log();
+    console.log(err.message || err);
+    console.log();
+    process.exit(1);
+  }
+
+  // "invalid" event fires when you have changed a file, and webpack is
+  // recompiling a bundle. WebpackDevServer takes care to pause serving the
+  // bundle, so if you refresh, it'll wait instead of serving the old one.
+  // "invalid" is short for "bundle invalidated", it doesn't imply any errors.
+  compiler.hooks.invalid.tap('invalid', () => {
+    if (isInteractive) {
+      clearConsole();
+    }
+    console.log('Compiling...');
+  });
+
+  let isFirstCompile = true;
+  let tsMessagesPromise;
+
+  if (useTypeScript) {
+    forkTsCheckerWebpackPlugin
+      .getCompilerHooks(compiler)
+      .waiting.tap('awaitingTypeScriptCheck', () => {
+        console.log(
+          chalk.yellow(
+            'Files successfully emitted, waiting for typecheck results...'
+          )
+        );
+      });
+  }
+
+  // "done" event fires when webpack has finished recompiling the bundle.
+  // Whether or not you have warnings or errors, you will get this event.
+  compiler.hooks.done.tap('done', async stats => {
+    if (isInteractive) {
+      clearConsole();
+    }
+
+    // We have switched off the default webpack output in WebpackDevServer
+    // options so we are going to "massage" the warnings and errors and present
+    // them in a readable focused way.
+    // We only construct the warnings and errors for speed:
+    // https://github.com/facebook/create-react-app/issues/4492#issuecomment-421959548
+    const statsData = stats.toJson({
+      all: false,
+      warnings: true,
+      errors: true,
+    });
+
+    const messages = formatWebpackMessages(statsData);
+    const isSuccessful = !messages.errors.length && !messages.warnings.length;
+    if (isSuccessful) {
+      console.log(chalk.green('Compiled successfully!'));
+    }
+    if (isSuccessful && (isInteractive || isFirstCompile)) {
+      printInstructions(appName, urls, useYarn);
+    }
+    isFirstCompile = false;
+
+    // If errors exist, only show errors.
+    if (messages.errors.length) {
+      // Only keep the first error. Others are often indicative
+      // of the same problem, but confuse the reader with noise.
+      if (messages.errors.length > 1) {
+        messages.errors.length = 1;
+      }
+      console.log(chalk.red('Failed to compile.\n'));
+      console.log(messages.errors.join('\n\n'));
+      return;
+    }
+
+    // Show warnings if no errors were found.
+    if (messages.warnings.length) {
+      console.log(chalk.yellow('Compiled with warnings.\n'));
+      console.log(messages.warnings.join('\n\n'));
+
+      // Teach some ESLint tricks.
+      console.log(
+        '\nSearch for the ' +
+          chalk.underline(chalk.yellow('keywords')) +
+          ' to learn more about each warning.'
+      );
+      console.log(
+        'To ignore, add ' +
+          chalk.cyan('// eslint-disable-next-line') +
+          ' to the line before.\n'
+      );
+    }
+  });
+
+  // You can safely remove this after ejecting.
+  // We only use this block for testing of Create React App itself:
+  const isSmokeTest = process.argv.some(
+    arg => arg.indexOf('--smoke-test') > -1
+  );
+  if (isSmokeTest) {
+    compiler.hooks.failed.tap('smokeTest', async () => {
+      await tsMessagesPromise;
+      process.exit(1);
+    });
+    compiler.hooks.done.tap('smokeTest', async stats => {
+      await tsMessagesPromise;
+      if (stats.hasErrors() || stats.hasWarnings()) {
+        process.exit(1);
+      } else {
+        process.exit(0);
+      }
+    });
+  }
+
+  return compiler;
+}
+
+function resolveLoopback(proxy) {
+  const o = url.parse(proxy);
+  o.host = undefined;
+  if (o.hostname !== 'localhost') {
+    return proxy;
+  }
+  // Unfortunately, many languages (unlike node) do not yet support IPv6.
+  // This means even though localhost resolves to ::1, the application
+  // must fall back to IPv4 (on 127.0.0.1).
+  // We can re-enable this in a few years.
+  /*try {
+    o.hostname = address.ipv6() ? '::1' : '127.0.0.1';
+  } catch (_ignored) {
+    o.hostname = '127.0.0.1';
+  }*/
+
+  try {
+    // Check if we're on a network; if we are, chances are we can resolve
+    // localhost. Otherwise, we can just be safe and assume localhost is
+    // IPv4 for maximum compatibility.
+    if (!address.ip()) {
+      o.hostname = '127.0.0.1';
+    }
+  } catch (_ignored) {
+    o.hostname = '127.0.0.1';
+  }
+  return url.format(o);
+}
+
+// We need to provide a custom onError function for httpProxyMiddleware.
+// It allows us to log custom error messages on the console.
+function onProxyError(proxy) {
+  return (err, req, res) => {
+    const host = req.headers && req.headers.host;
+    console.log(
+      chalk.red('Proxy error:') +
+        ' Could not proxy request ' +
+        chalk.cyan(req.url) +
+        ' from ' +
+        chalk.cyan(host) +
+        ' to ' +
+        chalk.cyan(proxy) +
+        '.'
+    );
+    console.log(
+      'See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (' +
+        chalk.cyan(err.code) +
+        ').'
+    );
+    console.log();
+
+    // And immediately send the proper error response to the client.
+    // Otherwise, the request will eventually timeout with ERR_EMPTY_RESPONSE on the client side.
+    if (res.writeHead && !res.headersSent) {
+      res.writeHead(500);
+    }
+    res.end(
+      'Proxy error: Could not proxy request ' +
+        req.url +
+        ' from ' +
+        host +
+        ' to ' +
+        proxy +
+        ' (' +
+        err.code +
+        ').'
+    );
+  };
+}
+
+function prepareProxy(proxy, appPublicFolder, servedPathname) {
+  // `proxy` lets you specify alternate servers for specific requests.
+  if (!proxy) {
+    return undefined;
+  }
+  if (typeof proxy !== 'string') {
+    console.log(
+      chalk.red('When specified, "proxy" in package.json must be a string.')
+    );
+    console.log(
+      chalk.red('Instead, the type of "proxy" was "' + typeof proxy + '".')
+    );
+    console.log(
+      chalk.red('Either remove "proxy" from package.json, or make it a string.')
+    );
+    process.exit(1);
+  }
+
+  // If proxy is specified, let it handle any request except for
+  // files in the public folder and requests to the WebpackDevServer socket endpoint.
+  // https://github.com/facebook/create-react-app/issues/6720
+  const sockPath = process.env.WDS_SOCKET_PATH || '/ws';
+  const isDefaultSockHost = !process.env.WDS_SOCKET_HOST;
+  function mayProxy(pathname) {
+    const maybePublicPath = path.resolve(
+      appPublicFolder,
+      pathname.replace(new RegExp('^' + servedPathname), '')
+    );
+    const isPublicFileRequest = fs.existsSync(maybePublicPath);
+    // used by webpackHotDevClient
+    const isWdsEndpointRequest =
+      isDefaultSockHost && pathname.startsWith(sockPath);
+    return !(isPublicFileRequest || isWdsEndpointRequest);
+  }
+
+  if (!/^http(s)?:\/\//.test(proxy)) {
+    console.log(
+      chalk.red(
+        'When "proxy" is specified in package.json it must start with either http:// or https://'
+      )
+    );
+    process.exit(1);
+  }
+
+  let target;
+  if (process.platform === 'win32') {
+    target = resolveLoopback(proxy);
+  } else {
+    target = proxy;
+  }
+  return [
+    {
+      target,
+      logLevel: 'silent',
+      // For single page apps, we generally want to fallback to /index.html.
+      // However we also want to respect `proxy` for API calls.
+      // So if `proxy` is specified as a string, we need to decide which fallback to use.
+      // We use a heuristic: We want to proxy all the requests that are not meant
+      // for static assets and as all the requests for static assets will be using
+      // `GET` method, we can proxy all non-`GET` requests.
+      // For `GET` requests, if request `accept`s text/html, we pick /index.html.
+      // Modern browsers include text/html into `accept` header when navigating.
+      // However API calls like `fetch()` won’t generally accept text/html.
+      // If this heuristic doesn’t work well for you, use `src/setupProxy.js`.
+      context: function (pathname, req) {
+        return (
+          req.method !== 'GET' ||
+          (mayProxy(pathname) &&
+            req.headers.accept &&
+            req.headers.accept.indexOf('text/html') === -1)
+        );
+      },
+      onProxyReq: proxyReq => {
+        // Browsers may send Origin headers even with same-origin
+        // requests. To prevent CORS issues, we have to change
+        // the Origin to match the target URL.
+        if (proxyReq.getHeader('origin')) {
+          proxyReq.setHeader('origin', target);
+        }
+      },
+      onError: onProxyError(target),
+      secure: false,
+      changeOrigin: true,
+      ws: true,
+      xfwd: true,
+    },
+  ];
+}
+
+function choosePort(host, defaultPort) {
+  return detect(defaultPort, host).then(
+    port =>
+      new Promise(resolve => {
+        if (port === defaultPort) {
+          return resolve(port);
+        }
+        const message =
+          process.platform !== 'win32' && defaultPort < 1024 && !isRoot()
+            ? `Admin permissions are required to run a server on a port below 1024.`
+            : `Something is already running on port ${defaultPort}.`;
+        if (isInteractive) {
+          clearConsole();
+          const existingProcess = getProcessForPort(defaultPort);
+          const question = {
+            type: 'confirm',
+            name: 'shouldChangePort',
+            message:
+              chalk.yellow(
+                message +
+                  `${existingProcess ? ` Probably:\n  ${existingProcess}` : ''}`
+              ) + '\n\nWould you like to run the app on another port instead?',
+            initial: true,
+          };
+          prompts(question).then(answer => {
+            if (answer.shouldChangePort) {
+              resolve(port);
+            } else {
+              resolve(null);
+            }
+          });
+        } else {
+          console.log(chalk.red(message));
+          resolve(null);
+        }
+      }),
+    err => {
+      throw new Error(
+        chalk.red(`Could not find an open port at ${chalk.bold(host)}.`) +
+          '\n' +
+          ('Network error message: ' + err.message || err) +
+          '\n'
+      );
+    }
+  );
+}
+
+module.exports = {
+  choosePort,
+  createCompiler,
+  prepareProxy,
+  prepareUrls,
+};
Index: frontend/node_modules/react-dev-utils/browsersHelper.js
===================================================================
--- frontend/node_modules/react-dev-utils/browsersHelper.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/browsersHelper.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+const browserslist = require('browserslist');
+const chalk = require('chalk');
+const os = require('os');
+const prompts = require('prompts');
+const pkgUp = require('pkg-up');
+const fs = require('fs');
+
+const defaultBrowsers = {
+  production: ['>0.2%', 'not dead', 'not op_mini all'],
+  development: [
+    'last 1 chrome version',
+    'last 1 firefox version',
+    'last 1 safari version',
+  ],
+};
+
+function shouldSetBrowsers(isInteractive) {
+  if (!isInteractive) {
+    return Promise.resolve(true);
+  }
+
+  const question = {
+    type: 'confirm',
+    name: 'shouldSetBrowsers',
+    message:
+      chalk.yellow("We're unable to detect target browsers.") +
+      `\n\nWould you like to add the defaults to your ${chalk.bold(
+        'package.json'
+      )}?`,
+    initial: true,
+  };
+
+  return prompts(question).then(answer => answer.shouldSetBrowsers);
+}
+
+function checkBrowsers(dir, isInteractive, retry = true) {
+  const current = browserslist.loadConfig({ path: dir });
+  if (current != null) {
+    return Promise.resolve(current);
+  }
+
+  if (!retry) {
+    return Promise.reject(
+      new Error(
+        chalk.red(
+          'As of react-scripts >=2 you must specify targeted browsers.'
+        ) +
+          os.EOL +
+          `Please add a ${chalk.underline(
+            'browserslist'
+          )} key to your ${chalk.bold('package.json')}.`
+      )
+    );
+  }
+
+  return shouldSetBrowsers(isInteractive).then(shouldSetBrowsers => {
+    if (!shouldSetBrowsers) {
+      return checkBrowsers(dir, isInteractive, false);
+    }
+
+    return (
+      pkgUp({ cwd: dir })
+        .then(filePath => {
+          if (filePath == null) {
+            return Promise.reject();
+          }
+          const pkg = JSON.parse(fs.readFileSync(filePath));
+          pkg['browserslist'] = defaultBrowsers;
+          fs.writeFileSync(filePath, JSON.stringify(pkg, null, 2) + os.EOL);
+
+          browserslist.clearCaches();
+          console.log();
+          console.log(
+            `${chalk.green('Set target browsers:')} ${chalk.cyan(
+              defaultBrowsers.join(', ')
+            )}`
+          );
+          console.log();
+        })
+        // Swallow any error
+        .catch(() => {})
+        .then(() => checkBrowsers(dir, isInteractive, false))
+    );
+  });
+}
+
+module.exports = { defaultBrowsers, checkBrowsers };
Index: frontend/node_modules/react-dev-utils/chalk.js
===================================================================
--- frontend/node_modules/react-dev-utils/chalk.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/chalk.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var chalk = require('chalk');
+
+module.exports = chalk;
Index: frontend/node_modules/react-dev-utils/checkRequiredFiles.js
===================================================================
--- frontend/node_modules/react-dev-utils/checkRequiredFiles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/checkRequiredFiles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+var chalk = require('chalk');
+
+function checkRequiredFiles(files) {
+  var currentFilePath;
+  try {
+    files.forEach(filePath => {
+      currentFilePath = filePath;
+      fs.accessSync(filePath, fs.F_OK);
+    });
+    return true;
+  } catch (err) {
+    var dirName = path.dirname(currentFilePath);
+    var fileName = path.basename(currentFilePath);
+    console.log(chalk.red('Could not find a required file.'));
+    console.log(chalk.red('  Name: ') + chalk.cyan(fileName));
+    console.log(chalk.red('  Searched in: ') + chalk.cyan(dirName));
+    return false;
+  }
+}
+
+module.exports = checkRequiredFiles;
Index: frontend/node_modules/react-dev-utils/clearConsole.js
===================================================================
--- frontend/node_modules/react-dev-utils/clearConsole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/clearConsole.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+function clearConsole() {
+  process.stdout.write(
+    process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'
+  );
+}
+
+module.exports = clearConsole;
Index: frontend/node_modules/react-dev-utils/crossSpawn.js
===================================================================
--- frontend/node_modules/react-dev-utils/crossSpawn.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/crossSpawn.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var crossSpawn = require('cross-spawn');
+
+module.exports = crossSpawn;
Index: frontend/node_modules/react-dev-utils/errorOverlayMiddleware.js
===================================================================
--- frontend/node_modules/react-dev-utils/errorOverlayMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/errorOverlayMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+const launchEditor = require('./launchEditor');
+const launchEditorEndpoint = require('./launchEditorEndpoint');
+
+module.exports = function createLaunchEditorMiddleware() {
+  return function launchEditorMiddleware(req, res, next) {
+    if (req.url.startsWith(launchEditorEndpoint)) {
+      const lineNumber = parseInt(req.query.lineNumber, 10) || 1;
+      const colNumber = parseInt(req.query.colNumber, 10) || 1;
+      launchEditor(req.query.fileName, lineNumber, colNumber);
+      res.end();
+    } else {
+      next();
+    }
+  };
+};
Index: frontend/node_modules/react-dev-utils/eslintFormatter.js
===================================================================
--- frontend/node_modules/react-dev-utils/eslintFormatter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/eslintFormatter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const path = require('path');
+const chalk = require('chalk');
+const stripAnsi = require('strip-ansi');
+const table = require('text-table');
+
+const cwd = process.cwd();
+
+const emitErrorsAsWarnings =
+  process.env.NODE_ENV === 'development' &&
+  process.env.ESLINT_NO_DEV_ERRORS === 'true';
+
+function isError(message) {
+  if (message.fatal || message.severity === 2) {
+    return true;
+  }
+  return false;
+}
+
+function getRelativePath(filePath) {
+  return path.relative(cwd, filePath);
+}
+
+function formatter(results) {
+  let output = '\n';
+  let hasErrors = false;
+  let reportContainsErrorRuleIDs = false;
+
+  results.forEach(result => {
+    let messages = result.messages;
+    if (messages.length === 0) {
+      return;
+    }
+
+    messages = messages.map(message => {
+      let messageType;
+      if (isError(message) && !emitErrorsAsWarnings) {
+        messageType = 'error';
+        hasErrors = true;
+        if (message.ruleId) {
+          reportContainsErrorRuleIDs = true;
+        }
+      } else {
+        messageType = 'warn';
+      }
+
+      let line = message.line || 0;
+      if (message.column) {
+        line += ':' + message.column;
+      }
+      let position = chalk.bold('Line ' + line + ':');
+      return [
+        '',
+        position,
+        messageType,
+        message.message.replace(/\.$/, ''),
+        chalk.underline(message.ruleId || ''),
+      ];
+    });
+
+    // if there are error messages, we want to show only errors
+    if (hasErrors) {
+      messages = messages.filter(m => m[2] === 'error');
+    }
+
+    // add color to rule keywords
+    messages.forEach(m => {
+      m[4] = m[2] === 'error' ? chalk.red(m[4]) : chalk.yellow(m[4]);
+      m.splice(2, 1);
+    });
+
+    let outputTable = table(messages, {
+      align: ['l', 'l', 'l'],
+      stringLength(str) {
+        return stripAnsi(str).length;
+      },
+    });
+
+    // print the filename and relative path
+    output += `${getRelativePath(result.filePath)}\n`;
+
+    // print the errors
+    output += `${outputTable}\n\n`;
+  });
+
+  if (reportContainsErrorRuleIDs) {
+    // Unlike with warnings, we have to do it here.
+    // We have similar code in react-scripts for warnings,
+    // but warnings can appear in multiple files so we only
+    // print it once at the end. For errors, however, we print
+    // it here because we always show at most one error, and
+    // we can only be sure it's an ESLint error before exiting
+    // this function.
+    output +=
+      'Search for the ' +
+      chalk.underline(chalk.red('keywords')) +
+      ' to learn more about each error.';
+  }
+
+  return output;
+}
+
+module.exports = formatter;
Index: frontend/node_modules/react-dev-utils/evalSourceMapMiddleware.js
===================================================================
--- frontend/node_modules/react-dev-utils/evalSourceMapMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/evalSourceMapMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+function base64SourceMap(source) {
+  const base64 = Buffer.from(JSON.stringify(source.map()), 'utf8').toString(
+    'base64'
+  );
+  return `data:application/json;charset=utf-8;base64,${base64}`;
+}
+
+function getSourceById(server, id) {
+  const module = Array.from(server._stats.compilation.modules).find(
+    (m) => server._stats.compilation.chunkGraph.getModuleId(m) == id,
+  );
+  return module.originalSource();
+}
+
+/*
+ * Middleware responsible for retrieving a generated source
+ * Receives a webpack internal url: "webpack-internal:///<module-id>"
+ * Returns a generated source: "<source-text><sourceMappingURL><sourceURL>"
+ *
+ * Based on EvalSourceMapDevToolModuleTemplatePlugin.js
+ */
+module.exports = function createEvalSourceMapMiddleware(server) {
+  return function handleWebpackInternalMiddleware(req, res, next) {
+    if (req.url.startsWith('/__get-internal-source')) {
+      const fileName = req.query.fileName;
+      const id = fileName.match(/webpack-internal:\/\/\/(.+)/)[1];
+      if (!id || !server._stats) {
+        next();
+      }
+
+      const source = getSourceById(server, id);
+      const sourceMapURL = `//# sourceMappingURL=${base64SourceMap(source)}`;
+      const sourceURL = `//# sourceURL=webpack-internal:///${module.id}`;
+      res.end(`${source.source()}\n${sourceMapURL}\n${sourceURL}`);
+    } else {
+      next();
+    }
+  };
+};
Index: frontend/node_modules/react-dev-utils/formatWebpackMessages.js
===================================================================
--- frontend/node_modules/react-dev-utils/formatWebpackMessages.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/formatWebpackMessages.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const friendlySyntaxErrorLabel = 'Syntax error:';
+
+function isLikelyASyntaxError(message) {
+  return message.indexOf(friendlySyntaxErrorLabel) !== -1;
+}
+
+// Cleans up webpack error messages.
+function formatMessage(message) {
+  let lines = [];
+
+  if (typeof message === 'string') {
+    lines = message.split('\n');
+  } else if ('message' in message) {
+    lines = message['message'].split('\n');
+  } else if (Array.isArray(message)) {
+    message.forEach(message => {
+      if ('message' in message) {
+        lines = message['message'].split('\n');
+      }
+    });
+  }
+
+  // Strip webpack-added headers off errors/warnings
+  // https://github.com/webpack/webpack/blob/master/lib/ModuleError.js
+  lines = lines.filter(line => !/Module [A-z ]+\(from/.test(line));
+
+  // Transform parsing error into syntax error
+  // TODO: move this to our ESLint formatter?
+  lines = lines.map(line => {
+    const parsingError = /Line (\d+):(?:(\d+):)?\s*Parsing error: (.+)$/.exec(
+      line
+    );
+    if (!parsingError) {
+      return line;
+    }
+    const [, errorLine, errorColumn, errorMessage] = parsingError;
+    return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})`;
+  });
+
+  message = lines.join('\n');
+  // Smoosh syntax errors (commonly found in CSS)
+  message = message.replace(
+    /SyntaxError\s+\((\d+):(\d+)\)\s*(.+?)\n/g,
+    `${friendlySyntaxErrorLabel} $3 ($1:$2)\n`
+  );
+  // Clean up export errors
+  message = message.replace(
+    /^.*export '(.+?)' was not found in '(.+?)'.*$/gm,
+    `Attempted import error: '$1' is not exported from '$2'.`
+  );
+  message = message.replace(
+    /^.*export 'default' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
+    `Attempted import error: '$2' does not contain a default export (imported as '$1').`
+  );
+  message = message.replace(
+    /^.*export '(.+?)' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
+    `Attempted import error: '$1' is not exported from '$3' (imported as '$2').`
+  );
+  lines = message.split('\n');
+
+  // Remove leading newline
+  if (lines.length > 2 && lines[1].trim() === '') {
+    lines.splice(1, 1);
+  }
+  // Clean up file name
+  lines[0] = lines[0].replace(/^(.*) \d+:\d+-\d+$/, '$1');
+
+  // Cleans up verbose "module not found" messages for files and packages.
+  if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
+    lines = [
+      lines[0],
+      lines[1]
+        .replace('Error: ', '')
+        .replace('Module not found: Cannot find file:', 'Cannot find file:'),
+    ];
+  }
+
+  // Add helpful message for users trying to use Sass for the first time
+  if (lines[1] && lines[1].match(/Cannot find module.+sass/)) {
+    lines[1] = 'To import Sass files, you first need to install sass.\n';
+    lines[1] +=
+      'Run `npm install sass` or `yarn add sass` inside your workspace.';
+  }
+
+  message = lines.join('\n');
+  // Internal stacks are generally useless so we strip them... with the
+  // exception of stacks containing `webpack:` because they're normally
+  // from user code generated by webpack. For more information see
+  // https://github.com/facebook/create-react-app/pull/1050
+  message = message.replace(
+    /^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm,
+    ''
+  ); // at ... ...:x:y
+  message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, ''); // at <anonymous>
+  lines = message.split('\n');
+
+  // Remove duplicated newlines
+  lines = lines.filter(
+    (line, index, arr) =>
+      index === 0 || line.trim() !== '' || line.trim() !== arr[index - 1].trim()
+  );
+
+  // Reassemble the message
+  message = lines.join('\n');
+  return message.trim();
+}
+
+function formatWebpackMessages(json) {
+  const formattedErrors = json.errors.map(formatMessage);
+  const formattedWarnings = json.warnings.map(formatMessage);
+  const result = { errors: formattedErrors, warnings: formattedWarnings };
+  if (result.errors.some(isLikelyASyntaxError)) {
+    // If there are any syntax errors, show just them.
+    result.errors = result.errors.filter(isLikelyASyntaxError);
+  }
+  return result;
+}
+
+module.exports = formatWebpackMessages;
Index: frontend/node_modules/react-dev-utils/getCSSModuleLocalIdent.js
===================================================================
--- frontend/node_modules/react-dev-utils/getCSSModuleLocalIdent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/getCSSModuleLocalIdent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const loaderUtils = require('loader-utils');
+const path = require('path');
+
+module.exports = function getLocalIdent(
+  context,
+  localIdentName,
+  localName,
+  options
+) {
+  // Use the filename or folder name, based on some uses the index.js / index.module.(css|scss|sass) project style
+  const fileNameOrFolder = context.resourcePath.match(
+    /index\.module\.(css|scss|sass)$/
+  )
+    ? '[folder]'
+    : '[name]';
+  // Create a hash based on a the file location and class name. Will be unique across a project, and close to globally unique.
+  const hash = loaderUtils.getHashDigest(
+    path.posix.relative(context.rootContext, context.resourcePath) + localName,
+    'md5',
+    'base64',
+    5
+  );
+  // Use loaderUtils to find the file or folder name
+  const className = loaderUtils.interpolateName(
+    context,
+    fileNameOrFolder + '_' + localName + '__' + hash,
+    options
+  );
+  // Remove the .module that appears in every classname when based on the file and replace all "." with "_".
+  return className.replace('.module_', '_').replace(/\./g, '_');
+};
Index: frontend/node_modules/react-dev-utils/getCacheIdentifier.js
===================================================================
--- frontend/node_modules/react-dev-utils/getCacheIdentifier.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/getCacheIdentifier.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+module.exports = function getCacheIdentifier(environment, packages) {
+  let cacheIdentifier = environment == null ? '' : environment.toString();
+  for (const packageName of packages) {
+    cacheIdentifier += `:${packageName}@`;
+    try {
+      cacheIdentifier += require(`${packageName}/package.json`).version;
+    } catch (_) {
+      // ignored
+    }
+  }
+  return cacheIdentifier;
+};
Index: frontend/node_modules/react-dev-utils/getProcessForPort.js
===================================================================
--- frontend/node_modules/react-dev-utils/getProcessForPort.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/getProcessForPort.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var chalk = require('chalk');
+var execSync = require('child_process').execSync;
+var execFileSync = require('child_process').execFileSync;
+var path = require('path');
+
+var execOptions = {
+  encoding: 'utf8',
+  stdio: [
+    'pipe', // stdin (default)
+    'pipe', // stdout (default)
+    'ignore', //stderr
+  ],
+};
+
+function isProcessAReactApp(processCommand) {
+  return /^node .*react-scripts\/scripts\/start\.js\s?$/.test(processCommand);
+}
+
+function getProcessIdOnPort(port) {
+  return execFileSync('lsof', ['-i:' + port, '-P', '-t', '-sTCP:LISTEN'], execOptions)
+    .split('\n')[0]
+    .trim();
+}
+
+function getPackageNameInDirectory(directory) {
+  var packagePath = path.join(directory.trim(), 'package.json');
+
+  try {
+    return require(packagePath).name;
+  } catch (e) {
+    return null;
+  }
+}
+
+function getProcessCommand(processId, processDirectory) {
+  var command = execSync(
+    'ps -o command -p ' + processId + ' | sed -n 2p',
+    execOptions
+  );
+
+  command = command.replace(/\n$/, '');
+
+  if (isProcessAReactApp(command)) {
+    const packageName = getPackageNameInDirectory(processDirectory);
+    return packageName ? packageName : command;
+  } else {
+    return command;
+  }
+}
+
+function getDirectoryOfProcessById(processId) {
+  return execSync(
+    'lsof -p ' +
+      processId +
+      ' | awk \'$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}\'',
+    execOptions
+  ).trim();
+}
+
+function getProcessForPort(port) {
+  try {
+    var processId = getProcessIdOnPort(port);
+    var directory = getDirectoryOfProcessById(processId);
+    var command = getProcessCommand(processId, directory);
+    return (
+      chalk.cyan(command) +
+      chalk.grey(' (pid ' + processId + ')\n') +
+      chalk.blue('  in ') +
+      chalk.cyan(directory)
+    );
+  } catch (e) {
+    return null;
+  }
+}
+
+module.exports = getProcessForPort;
Index: frontend/node_modules/react-dev-utils/getPublicUrlOrPath.js
===================================================================
--- frontend/node_modules/react-dev-utils/getPublicUrlOrPath.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/getPublicUrlOrPath.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const { URL } = require('url');
+
+module.exports = getPublicUrlOrPath;
+
+/**
+ * Returns a URL or a path with slash at the end
+ * In production can be URL, abolute path, relative path
+ * In development always will be an absolute path
+ * In development can use `path` module functions for operations
+ *
+ * @param {boolean} isEnvDevelopment
+ * @param {(string|undefined)} homepage a valid url or pathname
+ * @param {(string|undefined)} envPublicUrl a valid url or pathname
+ * @returns {string}
+ */
+function getPublicUrlOrPath(isEnvDevelopment, homepage, envPublicUrl) {
+  const stubDomain = 'https://create-react-app.dev';
+
+  if (envPublicUrl) {
+    // ensure last slash exists
+    envPublicUrl = envPublicUrl.endsWith('/')
+      ? envPublicUrl
+      : envPublicUrl + '/';
+
+    // validate if `envPublicUrl` is a URL or path like
+    // `stubDomain` is ignored if `envPublicUrl` contains a domain
+    const validPublicUrl = new URL(envPublicUrl, stubDomain);
+
+    return isEnvDevelopment
+      ? envPublicUrl.startsWith('.')
+        ? '/'
+        : validPublicUrl.pathname
+      : // Some apps do not use client-side routing with pushState.
+        // For these, "homepage" can be set to "." to enable relative asset paths.
+        envPublicUrl;
+  }
+
+  if (homepage) {
+    // strip last slash if exists
+    homepage = homepage.endsWith('/') ? homepage : homepage + '/';
+
+    // validate if `homepage` is a URL or path like and use just pathname
+    const validHomepagePathname = new URL(homepage, stubDomain).pathname;
+    return isEnvDevelopment
+      ? homepage.startsWith('.')
+        ? '/'
+        : validHomepagePathname
+      : // Some apps do not use client-side routing with pushState.
+      // For these, "homepage" can be set to "." to enable relative asset paths.
+      homepage.startsWith('.')
+      ? homepage
+      : validHomepagePathname;
+  }
+
+  return '/';
+}
Index: frontend/node_modules/react-dev-utils/globby.js
===================================================================
--- frontend/node_modules/react-dev-utils/globby.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/globby.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var globby = require('globby');
+
+module.exports = globby;
Index: frontend/node_modules/react-dev-utils/ignoredFiles.js
===================================================================
--- frontend/node_modules/react-dev-utils/ignoredFiles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/ignoredFiles.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const path = require('path');
+const escape = require('escape-string-regexp');
+
+module.exports = function ignoredFiles(appSrc) {
+  return new RegExp(
+    `^(?!${escape(
+      path.normalize(appSrc + '/').replace(/[\\]+/g, '/')
+    )}).+/node_modules/`,
+    'g'
+  );
+};
Index: frontend/node_modules/react-dev-utils/immer.js
===================================================================
--- frontend/node_modules/react-dev-utils/immer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/immer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var immer = require('immer');
+
+module.exports = immer;
Index: frontend/node_modules/react-dev-utils/launchEditor.js
===================================================================
--- frontend/node_modules/react-dev-utils/launchEditor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/launchEditor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,399 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const child_process = require('child_process');
+const os = require('os');
+const chalk = require('chalk');
+const shellQuote = require('shell-quote');
+
+function isTerminalEditor(editor) {
+  switch (editor) {
+    case 'vim':
+    case 'emacs':
+    case 'nano':
+      return true;
+  }
+  return false;
+}
+
+// Map from full process name to binary that starts the process
+// We can't just re-use full process name, because it will spawn a new instance
+// of the app every time
+const COMMON_EDITORS_OSX = {
+  '/Applications/Atom.app/Contents/MacOS/Atom': 'atom',
+  '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta':
+    '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',
+  '/Applications/Brackets.app/Contents/MacOS/Brackets': 'brackets',
+  '/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':
+    '/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',
+  '/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text':
+    '/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl',
+  '/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':
+    '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',
+  '/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',
+  '/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron':
+    'code-insiders',
+  '/Applications/VSCodium.app/Contents/MacOS/Electron': 'vscodium',
+  '/Applications/AppCode.app/Contents/MacOS/appcode':
+    '/Applications/AppCode.app/Contents/MacOS/appcode',
+  '/Applications/CLion.app/Contents/MacOS/clion':
+    '/Applications/CLion.app/Contents/MacOS/clion',
+  '/Applications/IntelliJ IDEA.app/Contents/MacOS/idea':
+    '/Applications/IntelliJ IDEA.app/Contents/MacOS/idea',
+  '/Applications/PhpStorm.app/Contents/MacOS/phpstorm':
+    '/Applications/PhpStorm.app/Contents/MacOS/phpstorm',
+  '/Applications/PyCharm.app/Contents/MacOS/pycharm':
+    '/Applications/PyCharm.app/Contents/MacOS/pycharm',
+  '/Applications/PyCharm CE.app/Contents/MacOS/pycharm':
+    '/Applications/PyCharm CE.app/Contents/MacOS/pycharm',
+  '/Applications/RubyMine.app/Contents/MacOS/rubymine':
+    '/Applications/RubyMine.app/Contents/MacOS/rubymine',
+  '/Applications/WebStorm.app/Contents/MacOS/webstorm':
+    '/Applications/WebStorm.app/Contents/MacOS/webstorm',
+  '/Applications/MacVim.app/Contents/MacOS/MacVim': 'mvim',
+  '/Applications/GoLand.app/Contents/MacOS/goland':
+    '/Applications/GoLand.app/Contents/MacOS/goland',
+  '/Applications/Rider.app/Contents/MacOS/rider':
+    '/Applications/Rider.app/Contents/MacOS/rider',
+};
+
+const COMMON_EDITORS_LINUX = {
+  atom: 'atom',
+  Brackets: 'brackets',
+  code: 'code',
+  'code-insiders': 'code-insiders',
+  vscodium: 'vscodium',
+  emacs: 'emacs',
+  gvim: 'gvim',
+  'idea.sh': 'idea',
+  'phpstorm.sh': 'phpstorm',
+  'pycharm.sh': 'pycharm',
+  'rubymine.sh': 'rubymine',
+  sublime_text: 'sublime_text',
+  vim: 'vim',
+  'webstorm.sh': 'webstorm',
+  'goland.sh': 'goland',
+  'rider.sh': 'rider',
+};
+
+const COMMON_EDITORS_WIN = [
+  'Brackets.exe',
+  'Code.exe',
+  'Code - Insiders.exe',
+  'VSCodium.exe',
+  'atom.exe',
+  'sublime_text.exe',
+  'notepad++.exe',
+  'clion.exe',
+  'clion64.exe',
+  'idea.exe',
+  'idea64.exe',
+  'phpstorm.exe',
+  'phpstorm64.exe',
+  'pycharm.exe',
+  'pycharm64.exe',
+  'rubymine.exe',
+  'rubymine64.exe',
+  'webstorm.exe',
+  'webstorm64.exe',
+  'goland.exe',
+  'goland64.exe',
+  'rider.exe',
+  'rider64.exe',
+];
+
+// Transpiled version of: /^([A-Za-z]:[/\\])?[\p{L}0-9/.\-_\\]+$/u
+// Non-transpiled version requires support for Unicode property regex. Allows
+// alphanumeric characters, periods, dashes, slashes, and underscores.
+const WINDOWS_FILE_NAME_WHITELIST = /^([A-Za-z]:[/\\])?(?:[\x2D-9A-Z\\_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEF\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7B9\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDF00-\uDF1C\uDF27\uDF30-\uDF45]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFF1]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])+$/;
+
+function addWorkspaceToArgumentsIfExists(args, workspace) {
+  if (workspace) {
+    args.unshift(workspace);
+  }
+  return args;
+}
+
+function getArgumentsForLineNumber(
+  editor,
+  fileName,
+  lineNumber,
+  colNumber,
+  workspace
+) {
+  const editorBasename = path.basename(editor).replace(/\.(exe|cmd|bat)$/i, '');
+  switch (editorBasename) {
+    case 'atom':
+    case 'Atom':
+    case 'Atom Beta':
+    case 'subl':
+    case 'sublime':
+    case 'sublime_text':
+      return [fileName + ':' + lineNumber + ':' + colNumber];
+    case 'wstorm':
+    case 'charm':
+      return [fileName + ':' + lineNumber];
+    case 'notepad++':
+      return ['-n' + lineNumber, '-c' + colNumber, fileName];
+    case 'vim':
+    case 'mvim':
+    case 'joe':
+    case 'gvim':
+      return ['+' + lineNumber, fileName];
+    case 'emacs':
+    case 'emacsclient':
+      return ['+' + lineNumber + ':' + colNumber, fileName];
+    case 'rmate':
+    case 'mate':
+    case 'mine':
+      return ['--line', lineNumber, fileName];
+    case 'code':
+    case 'Code':
+    case 'code-insiders':
+    case 'Code - Insiders':
+    case 'vscodium':
+    case 'VSCodium':
+      return addWorkspaceToArgumentsIfExists(
+        ['-g', fileName + ':' + lineNumber + ':' + colNumber],
+        workspace
+      );
+    case 'appcode':
+    case 'clion':
+    case 'clion64':
+    case 'idea':
+    case 'idea64':
+    case 'phpstorm':
+    case 'phpstorm64':
+    case 'pycharm':
+    case 'pycharm64':
+    case 'rubymine':
+    case 'rubymine64':
+    case 'webstorm':
+    case 'webstorm64':
+    case 'goland':
+    case 'goland64':
+    case 'rider':
+    case 'rider64':
+      return addWorkspaceToArgumentsIfExists(
+        ['--line', lineNumber, fileName],
+        workspace
+      );
+  }
+
+  // For all others, drop the lineNumber until we have
+  // a mapping above, since providing the lineNumber incorrectly
+  // can result in errors or confusing behavior.
+  return [fileName];
+}
+
+function guessEditor() {
+  // Explicit config always wins
+  if (process.env.REACT_EDITOR) {
+    return shellQuote.parse(process.env.REACT_EDITOR);
+  }
+
+  // We can find out which editor is currently running by:
+  // `ps x` on macOS and Linux
+  // `Get-Process` on Windows
+  try {
+    if (process.platform === 'darwin') {
+      const output = child_process.execSync('ps x').toString();
+      const processNames = Object.keys(COMMON_EDITORS_OSX);
+      for (let i = 0; i < processNames.length; i++) {
+        const processName = processNames[i];
+        if (output.indexOf(processName) !== -1) {
+          return [COMMON_EDITORS_OSX[processName]];
+        }
+      }
+    } else if (process.platform === 'win32') {
+      // Some processes need elevated rights to get its executable path.
+      // Just filter them out upfront. This also saves 10-20ms on the command.
+      const output = child_process
+        .execSync(
+          'wmic process where "executablepath is not null" get executablepath'
+        )
+        .toString();
+      const runningProcesses = output.split('\r\n');
+      for (let i = 0; i < runningProcesses.length; i++) {
+        const processPath = runningProcesses[i].trim();
+        const processName = path.basename(processPath);
+        if (COMMON_EDITORS_WIN.indexOf(processName) !== -1) {
+          return [processPath];
+        }
+      }
+    } else if (process.platform === 'linux') {
+      // --no-heading No header line
+      // x List all processes owned by you
+      // -o comm Need only names column
+      const output = child_process
+        .execSync('ps x --no-heading -o comm --sort=comm')
+        .toString();
+      const processNames = Object.keys(COMMON_EDITORS_LINUX);
+      for (let i = 0; i < processNames.length; i++) {
+        const processName = processNames[i];
+        if (output.indexOf(processName) !== -1) {
+          return [COMMON_EDITORS_LINUX[processName]];
+        }
+      }
+    }
+  } catch (error) {
+    // Ignore...
+  }
+
+  // Last resort, use old skool env vars
+  if (process.env.VISUAL) {
+    return [process.env.VISUAL];
+  } else if (process.env.EDITOR) {
+    return [process.env.EDITOR];
+  }
+
+  return [null];
+}
+
+function printInstructions(fileName, errorMessage) {
+  console.log();
+  console.log(
+    chalk.red('Could not open ' + path.basename(fileName) + ' in the editor.')
+  );
+  if (errorMessage) {
+    if (errorMessage[errorMessage.length - 1] !== '.') {
+      errorMessage += '.';
+    }
+    console.log(
+      chalk.red('The editor process exited with an error: ' + errorMessage)
+    );
+  }
+  console.log();
+  console.log(
+    'To set up the editor integration, add something like ' +
+      chalk.cyan('REACT_EDITOR=atom') +
+      ' to the ' +
+      chalk.green('.env.local') +
+      ' file in your project folder ' +
+      'and restart the development server. Learn more: ' +
+      chalk.green('https://goo.gl/MMTaZt')
+  );
+  console.log();
+}
+
+let _childProcess = null;
+function launchEditor(fileName, lineNumber, colNumber) {
+  if (!fs.existsSync(fileName)) {
+    return;
+  }
+
+  // Sanitize lineNumber to prevent malicious use on win32
+  // via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333
+  // and it should be a positive integer
+  if (!(Number.isInteger(lineNumber) && lineNumber > 0)) {
+    return;
+  }
+
+  // colNumber is optional, but should be a positive integer too
+  // default is 1
+  if (!(Number.isInteger(colNumber) && colNumber > 0)) {
+    colNumber = 1;
+  }
+
+  let [editor, ...args] = guessEditor();
+
+  if (!editor) {
+    printInstructions(fileName, null);
+    return;
+  }
+
+  if (editor.toLowerCase() === 'none') {
+    return;
+  }
+
+  if (
+    process.platform === 'linux' &&
+    fileName.startsWith('/mnt/') &&
+    /Microsoft/i.test(os.release())
+  ) {
+    // Assume WSL / "Bash on Ubuntu on Windows" is being used, and
+    // that the file exists on the Windows file system.
+    // `os.release()` is "4.4.0-43-Microsoft" in the current release
+    // build of WSL, see: https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364
+    // When a Windows editor is specified, interop functionality can
+    // handle the path translation, but only if a relative path is used.
+    fileName = path.relative('', fileName);
+  }
+
+  // cmd.exe on Windows is vulnerable to RCE attacks given a file name of the
+  // form "C:\Users\myusername\Downloads\& curl 172.21.93.52". Use a whitelist
+  // to validate user-provided file names. This doesn't cover the entire range
+  // of valid file names but should cover almost all of them in practice.
+  if (
+    process.platform === 'win32' &&
+    !WINDOWS_FILE_NAME_WHITELIST.test(fileName.trim())
+  ) {
+    console.log();
+    console.log(
+      chalk.red('Could not open ' + path.basename(fileName) + ' in the editor.')
+    );
+    console.log();
+    console.log(
+      'When running on Windows, file names are checked against a whitelist ' +
+        'to protect against remote code execution attacks. File names may ' +
+        'consist only of alphanumeric characters (all languages), periods, ' +
+        'dashes, slashes, and underscores.'
+    );
+    console.log();
+    return;
+  }
+
+  let workspace = null;
+  if (lineNumber) {
+    args = args.concat(
+      getArgumentsForLineNumber(
+        editor,
+        fileName,
+        lineNumber,
+        colNumber,
+        workspace
+      )
+    );
+  } else {
+    args.push(fileName);
+  }
+
+  if (_childProcess && isTerminalEditor(editor)) {
+    // There's an existing editor process already and it's attached
+    // to the terminal, so go kill it. Otherwise two separate editor
+    // instances attach to the stdin/stdout which gets confusing.
+    _childProcess.kill('SIGKILL');
+  }
+
+  if (process.platform === 'win32') {
+    // On Windows, launch the editor in a shell because spawn can only
+    // launch .exe files.
+    _childProcess = child_process.spawn(
+      'cmd.exe',
+      ['/C', editor].concat(args),
+      { stdio: 'inherit' }
+    );
+  } else {
+    _childProcess = child_process.spawn(editor, args, { stdio: 'inherit' });
+  }
+  _childProcess.on('exit', function (errorCode) {
+    _childProcess = null;
+
+    if (errorCode) {
+      printInstructions(fileName, '(code ' + errorCode + ')');
+    }
+  });
+
+  _childProcess.on('error', function (error) {
+    printInstructions(fileName, error.message);
+  });
+}
+
+module.exports = launchEditor;
Index: frontend/node_modules/react-dev-utils/launchEditorEndpoint.js
===================================================================
--- frontend/node_modules/react-dev-utils/launchEditorEndpoint.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/launchEditorEndpoint.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,10 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+// TODO: we might want to make this injectable to support DEV-time non-root URLs.
+module.exports = '/__open-stack-frame-in-editor';
Index: frontend/node_modules/react-dev-utils/node_modules/find-up/index.d.ts
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/find-up/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/find-up/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,138 @@
+/* eslint-disable @typescript-eslint/unified-signatures */
+import {Options as LocatePathOptions} from 'locate-path';
+
+declare const stop: unique symbol;
+
+declare namespace findUp {
+	interface Options extends LocatePathOptions {}
+
+	type StopSymbol = typeof stop;
+
+	type Match = string | StopSymbol | undefined;
+}
+
+declare const findUp: {
+	sync: {
+		/**
+		Synchronously check if a path exists.
+
+		@param path - Path to the file or directory.
+		@returns Whether the path exists.
+
+		@example
+		```
+		import findUp = require('find-up');
+
+		console.log(findUp.sync.exists('/Users/sindresorhus/unicorn.png'));
+		//=> true
+		```
+		*/
+		exists: (path: string) => boolean;
+
+		/**
+		Synchronously find a file or directory by walking up parent directories.
+
+		@param name - Name of the file or directory to find. Can be multiple.
+		@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
+		*/
+		(name: string | readonly string[], options?: findUp.Options): string | undefined;
+
+		/**
+		Synchronously find a file or directory by walking up parent directories.
+
+		@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
+		@returns The first path found or `undefined` if none could be found.
+
+		@example
+		```
+		import path = require('path');
+		import findUp = require('find-up');
+
+		console.log(findUp.sync(directory => {
+			const hasUnicorns = findUp.sync.exists(path.join(directory, 'unicorn.png'));
+			return hasUnicorns && directory;
+		}, {type: 'directory'}));
+		//=> '/Users/sindresorhus'
+		```
+		*/
+		(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;
+	};
+
+	/**
+	Check if a path exists.
+
+	@param path - Path to a file or directory.
+	@returns Whether the path exists.
+
+	@example
+	```
+	import findUp = require('find-up');
+
+	(async () => {
+		console.log(await findUp.exists('/Users/sindresorhus/unicorn.png'));
+		//=> true
+	})();
+	```
+	*/
+	exists: (path: string) => Promise<boolean>;
+
+	/**
+	Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.
+	*/
+	readonly stop: findUp.StopSymbol;
+
+	/**
+	Find a file or directory by walking up parent directories.
+
+	@param name - Name of the file or directory to find. Can be multiple.
+	@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
+
+	@example
+	```
+	// /
+	// └── Users
+	//     └── sindresorhus
+	//         ├── unicorn.png
+	//         └── foo
+	//             └── bar
+	//                 ├── baz
+	//                 └── example.js
+
+	// example.js
+	import findUp = require('find-up');
+
+	(async () => {
+		console.log(await findUp('unicorn.png'));
+		//=> '/Users/sindresorhus/unicorn.png'
+
+		console.log(await findUp(['rainbow.png', 'unicorn.png']));
+		//=> '/Users/sindresorhus/unicorn.png'
+	})();
+	```
+	*/
+	(name: string | readonly string[], options?: findUp.Options): Promise<string | undefined>;
+
+	/**
+	Find a file or directory by walking up parent directories.
+
+	@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
+	@returns The first path found or `undefined` if none could be found.
+
+	@example
+	```
+	import path = require('path');
+	import findUp = require('find-up');
+
+	(async () => {
+		console.log(await findUp(async directory => {
+			const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
+			return hasUnicorns && directory;
+		}, {type: 'directory'}));
+		//=> '/Users/sindresorhus'
+	})();
+	```
+	*/
+	(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.Options): Promise<string | undefined>;
+};
+
+export = findUp;
Index: frontend/node_modules/react-dev-utils/node_modules/find-up/index.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/find-up/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/find-up/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,89 @@
+'use strict';
+const path = require('path');
+const locatePath = require('locate-path');
+const pathExists = require('path-exists');
+
+const stop = Symbol('findUp.stop');
+
+module.exports = async (name, options = {}) => {
+	let directory = path.resolve(options.cwd || '');
+	const {root} = path.parse(directory);
+	const paths = [].concat(name);
+
+	const runMatcher = async locateOptions => {
+		if (typeof name !== 'function') {
+			return locatePath(paths, locateOptions);
+		}
+
+		const foundPath = await name(locateOptions.cwd);
+		if (typeof foundPath === 'string') {
+			return locatePath([foundPath], locateOptions);
+		}
+
+		return foundPath;
+	};
+
+	// eslint-disable-next-line no-constant-condition
+	while (true) {
+		// eslint-disable-next-line no-await-in-loop
+		const foundPath = await runMatcher({...options, cwd: directory});
+
+		if (foundPath === stop) {
+			return;
+		}
+
+		if (foundPath) {
+			return path.resolve(directory, foundPath);
+		}
+
+		if (directory === root) {
+			return;
+		}
+
+		directory = path.dirname(directory);
+	}
+};
+
+module.exports.sync = (name, options = {}) => {
+	let directory = path.resolve(options.cwd || '');
+	const {root} = path.parse(directory);
+	const paths = [].concat(name);
+
+	const runMatcher = locateOptions => {
+		if (typeof name !== 'function') {
+			return locatePath.sync(paths, locateOptions);
+		}
+
+		const foundPath = name(locateOptions.cwd);
+		if (typeof foundPath === 'string') {
+			return locatePath.sync([foundPath], locateOptions);
+		}
+
+		return foundPath;
+	};
+
+	// eslint-disable-next-line no-constant-condition
+	while (true) {
+		const foundPath = runMatcher({...options, cwd: directory});
+
+		if (foundPath === stop) {
+			return;
+		}
+
+		if (foundPath) {
+			return path.resolve(directory, foundPath);
+		}
+
+		if (directory === root) {
+			return;
+		}
+
+		directory = path.dirname(directory);
+	}
+};
+
+module.exports.exists = pathExists;
+
+module.exports.sync.exists = pathExists.sync;
+
+module.exports.stop = stop;
Index: frontend/node_modules/react-dev-utils/node_modules/find-up/license
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/find-up/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/find-up/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/react-dev-utils/node_modules/find-up/package.json
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/find-up/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/find-up/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+{
+	"name": "find-up",
+	"version": "5.0.0",
+	"description": "Find a file or directory by walking up parent directories",
+	"license": "MIT",
+	"repository": "sindresorhus/find-up",
+	"funding": "https://github.com/sponsors/sindresorhus",
+	"author": {
+		"name": "Sindre Sorhus",
+		"email": "sindresorhus@gmail.com",
+		"url": "https://sindresorhus.com"
+	},
+	"engines": {
+		"node": ">=10"
+	},
+	"scripts": {
+		"test": "xo && ava && tsd"
+	},
+	"files": [
+		"index.js",
+		"index.d.ts"
+	],
+	"keywords": [
+		"find",
+		"up",
+		"find-up",
+		"findup",
+		"look-up",
+		"look",
+		"file",
+		"search",
+		"match",
+		"package",
+		"resolve",
+		"parent",
+		"parents",
+		"folder",
+		"directory",
+		"walk",
+		"walking",
+		"path"
+	],
+	"dependencies": {
+		"locate-path": "^6.0.0",
+		"path-exists": "^4.0.0"
+	},
+	"devDependencies": {
+		"ava": "^2.1.0",
+		"is-path-inside": "^2.1.0",
+		"tempy": "^0.6.0",
+		"tsd": "^0.13.1",
+		"xo": "^0.33.0"
+	}
+}
Index: frontend/node_modules/react-dev-utils/node_modules/find-up/readme.md
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/find-up/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/find-up/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,151 @@
+# find-up [![Build Status](https://travis-ci.com/sindresorhus/find-up.svg?branch=master)](https://travis-ci.com/github/sindresorhus/find-up)
+
+> Find a file or directory by walking up parent directories
+
+## Install
+
+```
+$ npm install find-up
+```
+
+## Usage
+
+```
+/
+└── Users
+    └── sindresorhus
+        ├── unicorn.png
+        └── foo
+            └── bar
+                ├── baz
+                └── example.js
+```
+
+`example.js`
+
+```js
+const path = require('path');
+const findUp = require('find-up');
+
+(async () => {
+	console.log(await findUp('unicorn.png'));
+	//=> '/Users/sindresorhus/unicorn.png'
+
+	console.log(await findUp(['rainbow.png', 'unicorn.png']));
+	//=> '/Users/sindresorhus/unicorn.png'
+
+	console.log(await findUp(async directory => {
+		const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
+		return hasUnicorns && directory;
+	}, {type: 'directory'}));
+	//=> '/Users/sindresorhus'
+})();
+```
+
+## API
+
+### findUp(name, options?)
+### findUp(matcher, options?)
+
+Returns a `Promise` for either the path or `undefined` if it couldn't be found.
+
+### findUp([...name], options?)
+
+Returns a `Promise` for either the first path found (by respecting the order of the array) or `undefined` if none could be found.
+
+### findUp.sync(name, options?)
+### findUp.sync(matcher, options?)
+
+Returns a path or `undefined` if it couldn't be found.
+
+### findUp.sync([...name], options?)
+
+Returns the first path found (by respecting the order of the array) or `undefined` if none could be found.
+
+#### name
+
+Type: `string`
+
+Name of the file or directory to find.
+
+#### matcher
+
+Type: `Function`
+
+A function that will be called with each directory until it returns a `string` with the path, which stops the search, or the root directory has been reached and nothing was found. Useful if you want to match files with certain patterns, set of permissions, or other advanced use-cases.
+
+When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path.
+
+#### options
+
+Type: `object`
+
+##### cwd
+
+Type: `string`\
+Default: `process.cwd()`
+
+Directory to start from.
+
+##### type
+
+Type: `string`\
+Default: `'file'`\
+Values: `'file'` `'directory'`
+
+The type of paths that can match.
+
+##### allowSymlinks
+
+Type: `boolean`\
+Default: `true`
+
+Allow symbolic links to match if they point to the chosen path type.
+
+### findUp.exists(path)
+
+Returns a `Promise<boolean>` of whether the path exists.
+
+### findUp.sync.exists(path)
+
+Returns a `boolean` of whether the path exists.
+
+#### path
+
+Type: `string`
+
+Path to a file or directory.
+
+### findUp.stop
+
+A [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) that can be returned by a `matcher` function to stop the search and cause `findUp` to immediately return `undefined`. Useful as a performance optimization in case the current working directory is deeply nested in the filesystem.
+
+```js
+const path = require('path');
+const findUp = require('find-up');
+
+(async () => {
+	await findUp(directory => {
+		return path.basename(directory) === 'work' ? findUp.stop : 'logo.png';
+	});
+})();
+```
+
+## Related
+
+- [find-up-cli](https://github.com/sindresorhus/find-up-cli) - CLI for this module
+- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
+- [pkg-dir](https://github.com/sindresorhus/pkg-dir) - Find the root directory of an npm package
+- [resolve-from](https://github.com/sindresorhus/resolve-from) - Resolve the path of a module like `require.resolve()` but from a given path
+
+---
+
+<div align="center">
+	<b>
+		<a href="https://tidelift.com/subscription/pkg/npm-find-up?utm_source=npm-find-up&utm_medium=referral&utm_campaign=readme">Get professional support for 'find-up' with a Tidelift subscription</a>
+	</b>
+	<br>
+	<sub>
+		Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
+	</sub>
+</div>
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/LICENSE
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/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/react-dev-utils/node_modules/loader-utils/README.md
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,167 @@
+# loader-utils
+
+## Methods
+
+### `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`
+- `[contenthash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash)
+- `[<hashType>:contenthash:<digestType>:<length>]` optionally one can configure
+  - other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512`
+  - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64safe`
+  - and `length` the length in chars
+- `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash)
+- `[<hashType>:hash:<digestType>:<length>]` optionally one can configure
+  - other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512`
+  - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64safe`
+  - 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.
+
+`digestType` with `base64safe` don't contain `/`, `+` and `=` symbols.
+
+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.png"
+loaderUtils.interpolateName(loaderContext, "[sha512:hash:base64:7].[ext]", { content: ... });
+// => 2BKDTjl.png
+// use sha512 hash instead of xxhash64 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 `xxhash64`, `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`, `base64safe`
+- `maxLength` the maximum length in chars
+
+## License
+
+MIT (http://www.opensource.org/licenses/mit-license.php)
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/getHashDigest.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/getHashDigest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/getHashDigest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,136 @@
+"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-_",
+};
+
+/**
+ * @param {Uint32Array} uint32Array Treated as a long base-0x100000000 number, little endian
+ * @param {number} divisor The divisor
+ * @return {number} Modulo (remainder) of the division
+ */
+function divmod32(uint32Array, divisor) {
+  let carry = 0;
+  for (let i = uint32Array.length - 1; i >= 0; i--) {
+    const value = carry * 0x100000000 + uint32Array[i];
+    carry = value % divisor;
+    uint32Array[i] = Math.floor(value / divisor);
+  }
+  return carry;
+}
+
+function encodeBufferToBase(buffer, base, length) {
+  const encodeTable = baseEncodeTables[base];
+
+  if (!encodeTable) {
+    throw new Error("Unknown encoding base" + base);
+  }
+
+  // Input bits are only enough to generate this many characters
+  const limit = Math.ceil((buffer.length * 8) / Math.log2(base));
+  length = Math.min(length, limit);
+
+  // Most of the crypto digests (if not all) has length a multiple of 4 bytes.
+  // Fewer numbers in the array means faster math.
+  const uint32Array = new Uint32Array(Math.ceil(buffer.length / 4));
+
+  // Make sure the input buffer data is copied and is not mutated by reference.
+  // divmod32() would corrupt the BulkUpdateDecorator cache otherwise.
+  buffer.copy(Buffer.from(uint32Array.buffer));
+
+  let output = "";
+
+  for (let i = 0; i < length; i++) {
+    output = encodeTable[divmod32(uint32Array, base)] + output;
+  }
+
+  return output;
+}
+
+let crypto = undefined;
+let createXXHash64 = undefined;
+let createMd4 = undefined;
+let BatchedHash = undefined;
+let BulkUpdateDecorator = undefined;
+
+function getHashDigest(buffer, algorithm, digestType, maxLength) {
+  algorithm = algorithm || "xxhash64";
+  maxLength = maxLength || 9999;
+
+  let hash;
+
+  if (algorithm === "xxhash64") {
+    if (createXXHash64 === undefined) {
+      createXXHash64 = require("./hash/xxhash64");
+
+      if (BatchedHash === undefined) {
+        BatchedHash = require("./hash/BatchedHash");
+      }
+    }
+
+    hash = new BatchedHash(createXXHash64());
+  } else if (algorithm === "md4") {
+    if (createMd4 === undefined) {
+      createMd4 = require("./hash/md4");
+
+      if (BatchedHash === undefined) {
+        BatchedHash = require("./hash/BatchedHash");
+      }
+    }
+
+    hash = new BatchedHash(createMd4());
+  } else if (algorithm === "native-md4") {
+    if (typeof crypto === "undefined") {
+      crypto = require("crypto");
+
+      if (BulkUpdateDecorator === undefined) {
+        BulkUpdateDecorator = require("./hash/BulkUpdateDecorator");
+      }
+    }
+
+    hash = new BulkUpdateDecorator(() => crypto.createHash("md4"), "md4");
+  } else {
+    if (typeof crypto === "undefined") {
+      crypto = require("crypto");
+
+      if (BulkUpdateDecorator === undefined) {
+        BulkUpdateDecorator = require("./hash/BulkUpdateDecorator");
+      }
+    }
+
+    hash = new BulkUpdateDecorator(
+      () => crypto.createHash(algorithm),
+      algorithm
+    );
+  }
+
+  hash.update(buffer);
+
+  if (
+    digestType === "base26" ||
+    digestType === "base32" ||
+    digestType === "base36" ||
+    digestType === "base49" ||
+    digestType === "base52" ||
+    digestType === "base58" ||
+    digestType === "base62" ||
+    digestType === "base64safe"
+  ) {
+    return encodeBufferToBase(
+      hash.digest(),
+      digestType === "base64safe" ? 64 : digestType.substr(4),
+      maxLength
+    );
+  }
+
+  return hash.digest(digestType || "hex").substr(0, maxLength);
+}
+
+module.exports = getHashDigest;
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/BatchedHash.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/BatchedHash.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/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/react-dev-utils/node_modules/loader-utils/lib/hash/BulkUpdateDecorator.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/BulkUpdateDecorator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/BulkUpdateDecorator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,107 @@
+const BULK_SIZE = 2000;
+
+// We are using an object instead of a Map as this will stay static during the runtime
+// so access to it can be optimized by v8
+const digestCaches = {};
+
+class BulkUpdateDecorator {
+  /**
+   * @param {Hash | function(): Hash} hashOrFactory function to create a hash
+   * @param {string=} hashKey key for caching
+   */
+  constructor(hashOrFactory, hashKey) {
+    this.hashKey = hashKey;
+
+    if (typeof hashOrFactory === "function") {
+      this.hashFactory = hashOrFactory;
+      this.hash = undefined;
+    } else {
+      this.hashFactory = undefined;
+      this.hash = hashOrFactory;
+    }
+
+    this.buffer = "";
+  }
+
+  /**
+   * 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 (
+      inputEncoding !== undefined ||
+      typeof data !== "string" ||
+      data.length > BULK_SIZE
+    ) {
+      if (this.hash === undefined) {
+        this.hash = this.hashFactory();
+      }
+
+      if (this.buffer.length > 0) {
+        this.hash.update(this.buffer);
+        this.buffer = "";
+      }
+
+      this.hash.update(data, inputEncoding);
+    } else {
+      this.buffer += data;
+
+      if (this.buffer.length > BULK_SIZE) {
+        if (this.hash === undefined) {
+          this.hash = this.hashFactory();
+        }
+
+        this.hash.update(this.buffer);
+        this.buffer = "";
+      }
+    }
+
+    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) {
+    let digestCache;
+
+    const buffer = this.buffer;
+
+    if (this.hash === undefined) {
+      // short data for hash, we can use caching
+      const cacheKey = `${this.hashKey}-${encoding}`;
+
+      digestCache = digestCaches[cacheKey];
+
+      if (digestCache === undefined) {
+        digestCache = digestCaches[cacheKey] = new Map();
+      }
+
+      const cacheEntry = digestCache.get(buffer);
+
+      if (cacheEntry !== undefined) {
+        return cacheEntry;
+      }
+
+      this.hash = this.hashFactory();
+    }
+
+    if (buffer.length > 0) {
+      this.hash.update(buffer);
+    }
+
+    const digestResult = this.hash.digest(encoding);
+
+    if (digestCache !== undefined) {
+      digestCache.set(buffer, digestResult);
+    }
+
+    return digestResult;
+  }
+}
+
+module.exports = BulkUpdateDecorator;
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/md4.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/md4.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/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
+    "AGFzbQEAAAABCAJgAX8AYAAAAwUEAQAAAAUDAQABBhoFfwFBAAt/AUEAC38BQQALfwFBAAt/AUEACwciBARpbml0AAAGdXBkYXRlAAIFZmluYWwAAwZtZW1vcnkCAAqFEAQmAEGBxpS6BiQBQYnXtv5+JAJB/rnrxXkkA0H2qMmBASQEQQAkAAvMCgEYfyMBIQojAiEGIwMhByMEIQgDQCAAIAVLBEAgBSgCCCINIAcgBiAFKAIEIgsgCCAHIAUoAgAiDCAKIAggBiAHIAhzcXNqakEDdyIDIAYgB3Nxc2pqQQd3IgEgAyAGc3FzampBC3chAiAFKAIUIg8gASACIAUoAhAiCSADIAEgBSgCDCIOIAYgAyACIAEgA3Nxc2pqQRN3IgQgASACc3FzampBA3ciAyACIARzcXNqakEHdyEBIAUoAiAiEiADIAEgBSgCHCIRIAQgAyAFKAIYIhAgAiAEIAEgAyAEc3FzampBC3ciAiABIANzcXNqakETdyIEIAEgAnNxc2pqQQN3IQMgBSgCLCIVIAQgAyAFKAIoIhQgAiAEIAUoAiQiEyABIAIgAyACIARzcXNqakEHdyIBIAMgBHNxc2pqQQt3IgIgASADc3FzampBE3chBCAPIBAgCSAVIBQgEyAFKAI4IhYgAiAEIAUoAjQiFyABIAIgBSgCMCIYIAMgASAEIAEgAnNxc2pqQQN3IgEgAiAEc3FzampBB3ciAiABIARzcXNqakELdyIDIAkgAiAMIAEgBSgCPCIJIAQgASADIAEgAnNxc2pqQRN3IgEgAiADcnEgAiADcXJqakGZ84nUBWpBA3ciAiABIANycSABIANxcmpqQZnzidQFakEFdyIEIAEgAnJxIAEgAnFyaiASakGZ84nUBWpBCXciAyAPIAQgCyACIBggASADIAIgBHJxIAIgBHFyampBmfOJ1AVqQQ13IgEgAyAEcnEgAyAEcXJqakGZ84nUBWpBA3ciAiABIANycSABIANxcmpqQZnzidQFakEFdyIEIAEgAnJxIAEgAnFyampBmfOJ1AVqQQl3IgMgECAEIAIgFyABIAMgAiAEcnEgAiAEcXJqakGZ84nUBWpBDXciASADIARycSADIARxcmogDWpBmfOJ1AVqQQN3IgIgASADcnEgASADcXJqakGZ84nUBWpBBXciBCABIAJycSABIAJxcmpqQZnzidQFakEJdyIDIBEgBCAOIAIgFiABIAMgAiAEcnEgAiAEcXJqakGZ84nUBWpBDXciASADIARycSADIARxcmpqQZnzidQFakEDdyICIAEgA3JxIAEgA3FyampBmfOJ1AVqQQV3IgQgASACcnEgASACcXJqakGZ84nUBWpBCXciAyAMIAIgAyAJIAEgAyACIARycSACIARxcmpqQZnzidQFakENdyIBcyAEc2pqQaHX5/YGakEDdyICIAQgASACcyADc2ogEmpBodfn9gZqQQl3IgRzIAFzampBodfn9gZqQQt3IgMgAiADIBggASADIARzIAJzampBodfn9gZqQQ93IgFzIARzaiANakGh1+f2BmpBA3ciAiAUIAQgASACcyADc2pqQaHX5/YGakEJdyIEcyABc2pqQaHX5/YGakELdyIDIAsgAiADIBYgASADIARzIAJzampBodfn9gZqQQ93IgFzIARzampBodfn9gZqQQN3IgIgEyAEIAEgAnMgA3NqakGh1+f2BmpBCXciBHMgAXNqakGh1+f2BmpBC3chAyAKIA4gAiADIBcgASADIARzIAJzampBodfn9gZqQQ93IgFzIARzampBodfn9gZqQQN3IgJqIQogBiAJIAEgESADIAIgFSAEIAEgAnMgA3NqakGh1+f2BmpBCXciBHMgAXNqakGh1+f2BmpBC3ciAyAEcyACc2pqQaHX5/YGakEPd2ohBiADIAdqIQcgBCAIaiEIIAVBQGshBQwBCwsgCiQBIAYkAiAHJAMgCCQECw0AIAAQASMAIABqJAAL/wQCA38BfiMAIABqrUIDhiEEIABByABqQUBxIgJBCGshAyAAIgFBAWohACABQYABOgAAA0AgACACSUEAIABBB3EbBEAgAEEAOgAAIABBAWohAAwBCwsDQCAAIAJJBEAgAEIANwMAIABBCGohAAwBCwsgAyAENwMAIAIQAUEAIwGtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEIIwKtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEQIwOtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEYIwStIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAAs=",
+    "base64"
+  )
+);
+//#endregion
+
+module.exports = create.bind(null, md4, [], 64, 32);
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/wasm-hash.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/wasm-hash.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/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/react-dev-utils/node_modules/loader-utils/lib/hash/xxhash64.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/xxhash64.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/hash/xxhash64.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: xxhash64 (../../../assembly/hash/xxhash64.asm.ts) --initialMemory 1
+const xxhash64 = new WebAssembly.Module(
+  Buffer.from(
+    // 1173 bytes
+    "AGFzbQEAAAABCAJgAX8AYAAAAwQDAQAABQMBAAEGGgV+AUIAC34BQgALfgFCAAt+AUIAC34BQgALByIEBGluaXQAAAZ1cGRhdGUAAQVmaW5hbAACBm1lbW9yeQIACrUIAzAAQtbrgu7q/Yn14AAkAELP1tO+0ser2UIkAUIAJAJC+erQ0OfJoeThACQDQgAkBAvUAQIBfwR+IABFBEAPCyMEIACtfCQEIwAhAiMBIQMjAiEEIwMhBQNAIAIgASkDAELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiECIAMgASkDCELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiEDIAQgASkDEELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiEEIAUgASkDGELP1tO+0ser2UJ+fEIfiUKHla+vmLbem55/fiEFIAAgAUEgaiIBSw0ACyACJAAgAyQBIAQkAiAFJAMLqwYCAX8EfiMEQgBSBH4jACICQgGJIwEiA0IHiXwjAiIEQgyJfCMDIgVCEol8IAJCz9bTvtLHq9lCfkIfiUKHla+vmLbem55/foVCh5Wvr5i23puef35CnaO16oOxjYr6AH0gA0LP1tO+0ser2UJ+Qh+JQoeVr6+Ytt6bnn9+hUKHla+vmLbem55/fkKdo7Xqg7GNivoAfSAEQs/W077Sx6vZQn5CH4lCh5Wvr5i23puef36FQoeVr6+Ytt6bnn9+Qp2jteqDsY2K+gB9IAVCz9bTvtLHq9lCfkIfiUKHla+vmLbem55/foVCh5Wvr5i23puef35CnaO16oOxjYr6AH0FQsXP2bLx5brqJwsjBCAArXx8IQIDQCABQQhqIABNBEAgAiABKQMAQs/W077Sx6vZQn5CH4lCh5Wvr5i23puef36FQhuJQoeVr6+Ytt6bnn9+Qp2jteqDsY2K+gB9IQIgAUEIaiEBDAELCyABQQRqIABNBEACfyACIAE1AgBCh5Wvr5i23puef36FQheJQs/W077Sx6vZQn5C+fPd8Zn2masWfCECIAFBBGoLIQELA0AgACABRwRAIAIgATEAAELFz9my8eW66id+hUILiUKHla+vmLbem55/fiECIAFBAWohAQwBCwtBACACIAJCIYiFQs/W077Sx6vZQn4iAiACQh2IhUL5893xmfaZqxZ+IgIgAkIgiIUiAkIgiCIDQv//A4NCIIYgA0KAgPz/D4NCEIiEIgNC/4GAgPAfg0IQhiADQoD+g4CA4D+DQgiIhCIDQo+AvIDwgcAHg0IIhiADQvCBwIeAnoD4AINCBIiEIgNChoyYsODAgYMGfEIEiEKBgoSIkKDAgAGDQid+IANCsODAgYOGjJgwhHw3AwBBCCACQv////8PgyICQv//A4NCIIYgAkKAgPz/D4NCEIiEIgJC/4GAgPAfg0IQhiACQoD+g4CA4D+DQgiIhCICQo+AvIDwgcAHg0IIhiACQvCBwIeAnoD4AINCBIiEIgJChoyYsODAgYMGfEIEiEKBgoSIkKDAgAGDQid+IAJCsODAgYOGjJgwhHw3AwAL",
+    "base64"
+  )
+);
+//#endregion
+
+module.exports = create.bind(null, xxhash64, [], 32, 16);
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/index.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,11 @@
+"use strict";
+
+const isUrlRequest = require("./isUrlRequest");
+const urlToRequest = require("./urlToRequest");
+const getHashDigest = require("./getHashDigest");
+const interpolateName = require("./interpolateName");
+
+exports.urlToRequest = urlToRequest;
+exports.getHashDigest = getHashDigest;
+exports.interpolateName = interpolateName;
+exports.isUrlRequest = isUrlRequest;
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/interpolateName.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/interpolateName.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/interpolateName.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,117 @@
+"use strict";
+
+const path = require("path");
+const getHashDigest = require("./getHashDigest");
+
+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 {
+      // 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*(?:safe)?))?(?::(\d+))?\]/gi,
+        (all, hashType, digestType, maxLength) =>
+          getHashDigest(content, hashType, digestType, parseInt(maxLength, 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/react-dev-utils/node_modules/loader-utils/lib/isUrlRequest.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/isUrlRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/isUrlRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,31 @@
+"use strict";
+
+const path = require("path");
+
+function isUrlRequest(url) {
+  // An URL is not an request if
+
+  // 1. Allow `data URI`
+  if (/^data:/i.test(url)) {
+    return true;
+  }
+
+  // 2. 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;
+  }
+
+  // 3. It's a protocol-relative
+  if (/^\/\//.test(url)) {
+    return false;
+  }
+
+  // 4. It's some kind of url for a template
+  if (/^#/.test(url)) {
+    return false;
+  }
+
+  return true;
+}
+
+module.exports = isUrlRequest;
Index: frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/urlToRequest.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/lib/urlToRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/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/react-dev-utils/node_modules/loader-utils/package.json
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/loader-utils/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/loader-utils/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+{
+  "name": "loader-utils",
+  "version": "3.3.1",
+  "author": "Tobias Koppers @sokra",
+  "description": "utils for webpack loaders",
+  "dependencies": {},
+  "scripts": {
+    "lint": "prettier --list-different . && eslint .",
+    "pretest": "yarn lint",
+    "test": "jest",
+    "test:only": "jest --coverage",
+    "test:ci": "yarn test:only",
+    "release": "yarn test && standard-version"
+  },
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/webpack/loader-utils.git"
+  },
+  "engines": {
+    "node": ">= 12.13.0"
+  },
+  "devDependencies": {
+    "coveralls": "^3.1.1",
+    "eslint": "^8.0.1",
+    "eslint-plugin-node": "^11.1.0",
+    "jest": "^27.3.1",
+    "prettier": "^2.4.1",
+    "standard-version": "^9.3.2"
+  },
+  "main": "lib/index.js",
+  "files": [
+    "lib"
+  ]
+}
Index: frontend/node_modules/react-dev-utils/node_modules/locate-path/index.d.ts
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/locate-path/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/locate-path/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,83 @@
+declare namespace locatePath {
+	interface Options {
+		/**
+		Current working directory.
+
+		@default process.cwd()
+		*/
+		readonly cwd?: string;
+
+		/**
+		Type of path to match.
+
+		@default 'file'
+		*/
+		readonly type?: 'file' | 'directory';
+
+		/**
+		Allow symbolic links to match if they point to the requested path type.
+
+		@default true
+		*/
+		readonly allowSymlinks?: boolean;
+	}
+
+	interface AsyncOptions extends Options {
+		/**
+		Number of concurrently pending promises. Minimum: `1`.
+
+		@default Infinity
+		*/
+		readonly concurrency?: number;
+
+		/**
+		Preserve `paths` order when searching.
+
+		Disable this to improve performance if you don't care about the order.
+
+		@default true
+		*/
+		readonly preserveOrder?: boolean;
+	}
+}
+
+declare const locatePath: {
+	/**
+	Synchronously get the first path that exists on disk of multiple paths.
+
+	@param paths - Paths to check.
+	@returns The first path that exists or `undefined` if none exists.
+	*/
+	sync: (
+		paths: Iterable<string>,
+		options?: locatePath.Options
+	) => string | undefined;
+
+	/**
+	Get the first path that exists on disk of multiple paths.
+
+	@param paths - Paths to check.
+	@returns The first path that exists or `undefined` if none exists.
+
+	@example
+	```
+	import locatePath = require('locate-path');
+
+	const files = [
+		'unicorn.png',
+		'rainbow.png', // Only this one actually exists on disk
+		'pony.png'
+	];
+
+	(async () => {
+		console(await locatePath(files));
+		//=> 'rainbow'
+	})();
+	```
+	*/
+	(paths: Iterable<string>, options?: locatePath.AsyncOptions): Promise<
+	string | undefined
+	>;
+};
+
+export = locatePath;
Index: frontend/node_modules/react-dev-utils/node_modules/locate-path/index.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/locate-path/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/locate-path/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,68 @@
+'use strict';
+const path = require('path');
+const fs = require('fs');
+const {promisify} = require('util');
+const pLocate = require('p-locate');
+
+const fsStat = promisify(fs.stat);
+const fsLStat = promisify(fs.lstat);
+
+const typeMappings = {
+	directory: 'isDirectory',
+	file: 'isFile'
+};
+
+function checkType({type}) {
+	if (type in typeMappings) {
+		return;
+	}
+
+	throw new Error(`Invalid type specified: ${type}`);
+}
+
+const matchType = (type, stat) => type === undefined || stat[typeMappings[type]]();
+
+module.exports = async (paths, options) => {
+	options = {
+		cwd: process.cwd(),
+		type: 'file',
+		allowSymlinks: true,
+		...options
+	};
+
+	checkType(options);
+
+	const statFn = options.allowSymlinks ? fsStat : fsLStat;
+
+	return pLocate(paths, async path_ => {
+		try {
+			const stat = await statFn(path.resolve(options.cwd, path_));
+			return matchType(options.type, stat);
+		} catch {
+			return false;
+		}
+	}, options);
+};
+
+module.exports.sync = (paths, options) => {
+	options = {
+		cwd: process.cwd(),
+		allowSymlinks: true,
+		type: 'file',
+		...options
+	};
+
+	checkType(options);
+
+	const statFn = options.allowSymlinks ? fs.statSync : fs.lstatSync;
+
+	for (const path_ of paths) {
+		try {
+			const stat = statFn(path.resolve(options.cwd, path_));
+
+			if (matchType(options.type, stat)) {
+				return path_;
+			}
+		} catch {}
+	}
+};
Index: frontend/node_modules/react-dev-utils/node_modules/locate-path/license
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/locate-path/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/locate-path/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/react-dev-utils/node_modules/locate-path/package.json
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/locate-path/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/locate-path/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+{
+	"name": "locate-path",
+	"version": "6.0.0",
+	"description": "Get the first path that exists on disk of multiple paths",
+	"license": "MIT",
+	"repository": "sindresorhus/locate-path",
+	"funding": "https://github.com/sponsors/sindresorhus",
+	"author": {
+		"name": "Sindre Sorhus",
+		"email": "sindresorhus@gmail.com",
+		"url": "https://sindresorhus.com"
+	},
+	"engines": {
+		"node": ">=10"
+	},
+	"scripts": {
+		"test": "xo && ava && tsd"
+	},
+	"files": [
+		"index.js",
+		"index.d.ts"
+	],
+	"keywords": [
+		"locate",
+		"path",
+		"paths",
+		"file",
+		"files",
+		"exists",
+		"find",
+		"finder",
+		"search",
+		"searcher",
+		"array",
+		"iterable",
+		"iterator"
+	],
+	"dependencies": {
+		"p-locate": "^5.0.0"
+	},
+	"devDependencies": {
+		"ava": "^2.4.0",
+		"tsd": "^0.13.1",
+		"xo": "^0.32.1"
+	}
+}
Index: frontend/node_modules/react-dev-utils/node_modules/locate-path/readme.md
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/locate-path/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/locate-path/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,125 @@
+# locate-path [![Build Status](https://travis-ci.com/sindresorhus/locate-path.svg?branch=master)](https://travis-ci.com/github/sindresorhus/locate-path)
+
+> Get the first path that exists on disk of multiple paths
+
+## Install
+
+```
+$ npm install locate-path
+```
+
+## Usage
+
+Here we find the first file that exists on disk, in array order.
+
+```js
+const locatePath = require('locate-path');
+
+const files = [
+	'unicorn.png',
+	'rainbow.png', // Only this one actually exists on disk
+	'pony.png'
+];
+
+(async () => {
+	console(await locatePath(files));
+	//=> 'rainbow'
+})();
+```
+
+## API
+
+### locatePath(paths, options?)
+
+Returns a `Promise<string>` for the first path that exists or `undefined` if none exists.
+
+#### paths
+
+Type: `Iterable<string>`
+
+Paths to check.
+
+#### options
+
+Type: `object`
+
+##### concurrency
+
+Type: `number`\
+Default: `Infinity`\
+Minimum: `1`
+
+Number of concurrently pending promises.
+
+##### preserveOrder
+
+Type: `boolean`\
+Default: `true`
+
+Preserve `paths` order when searching.
+
+Disable this to improve performance if you don't care about the order.
+
+##### cwd
+
+Type: `string`\
+Default: `process.cwd()`
+
+Current working directory.
+
+##### type
+
+Type: `string`\
+Default: `'file'`\
+Values: `'file' | 'directory'`
+
+The type of paths that can match.
+
+##### allowSymlinks
+
+Type: `boolean`\
+Default: `true`
+
+Allow symbolic links to match if they point to the chosen path type.
+
+### locatePath.sync(paths, options?)
+
+Returns the first path that exists or `undefined` if none exists.
+
+#### paths
+
+Type: `Iterable<string>`
+
+Paths to check.
+
+#### options
+
+Type: `object`
+
+##### cwd
+
+Same as above.
+
+##### type
+
+Same as above.
+
+##### allowSymlinks
+
+Same as above.
+
+## Related
+
+- [path-exists](https://github.com/sindresorhus/path-exists) - Check if a path exists
+
+---
+
+<div align="center">
+	<b>
+		<a href="https://tidelift.com/subscription/pkg/npm-locate-path?utm_source=npm-locate-path&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
+	</b>
+	<br>
+	<sub>
+		Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
+	</sub>
+</div>
Index: frontend/node_modules/react-dev-utils/node_modules/p-limit/index.d.ts
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-limit/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-limit/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,42 @@
+declare namespace pLimit {
+	interface Limit {
+		/**
+		The number of promises that are currently running.
+		*/
+		readonly activeCount: number;
+
+		/**
+		The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
+		*/
+		readonly pendingCount: number;
+
+		/**
+		Discard pending promises that are waiting to run.
+
+		This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
+
+		Note: This does not cancel promises that are already running.
+		*/
+		clearQueue: () => void;
+
+		/**
+		@param fn - Promise-returning/async function.
+		@param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.
+		@returns The promise returned by calling `fn(...arguments)`.
+		*/
+		<Arguments extends unknown[], ReturnType>(
+			fn: (...arguments: Arguments) => PromiseLike<ReturnType> | ReturnType,
+			...arguments: Arguments
+		): Promise<ReturnType>;
+	}
+}
+
+/**
+Run multiple promise-returning & async functions with limited concurrency.
+
+@param concurrency - Concurrency limit. Minimum: `1`.
+@returns A `limit` function.
+*/
+declare function pLimit(concurrency: number): pLimit.Limit;
+
+export = pLimit;
Index: frontend/node_modules/react-dev-utils/node_modules/p-limit/index.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-limit/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-limit/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,71 @@
+'use strict';
+const Queue = require('yocto-queue');
+
+const pLimit = concurrency => {
+	if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
+		throw new TypeError('Expected `concurrency` to be a number from 1 and up');
+	}
+
+	const queue = new Queue();
+	let activeCount = 0;
+
+	const next = () => {
+		activeCount--;
+
+		if (queue.size > 0) {
+			queue.dequeue()();
+		}
+	};
+
+	const run = async (fn, resolve, ...args) => {
+		activeCount++;
+
+		const result = (async () => fn(...args))();
+
+		resolve(result);
+
+		try {
+			await result;
+		} catch {}
+
+		next();
+	};
+
+	const enqueue = (fn, resolve, ...args) => {
+		queue.enqueue(run.bind(null, fn, resolve, ...args));
+
+		(async () => {
+			// This function needs to wait until the next microtask before comparing
+			// `activeCount` to `concurrency`, because `activeCount` is updated asynchronously
+			// when the run function is dequeued and called. The comparison in the if-statement
+			// needs to happen asynchronously as well to get an up-to-date value for `activeCount`.
+			await Promise.resolve();
+
+			if (activeCount < concurrency && queue.size > 0) {
+				queue.dequeue()();
+			}
+		})();
+	};
+
+	const generator = (fn, ...args) => new Promise(resolve => {
+		enqueue(fn, resolve, ...args);
+	});
+
+	Object.defineProperties(generator, {
+		activeCount: {
+			get: () => activeCount
+		},
+		pendingCount: {
+			get: () => queue.size
+		},
+		clearQueue: {
+			value: () => {
+				queue.clear();
+			}
+		}
+	});
+
+	return generator;
+};
+
+module.exports = pLimit;
Index: frontend/node_modules/react-dev-utils/node_modules/p-limit/license
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-limit/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-limit/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/react-dev-utils/node_modules/p-limit/package.json
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-limit/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-limit/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+{
+	"name": "p-limit",
+	"version": "3.1.0",
+	"description": "Run multiple promise-returning & async functions with limited concurrency",
+	"license": "MIT",
+	"repository": "sindresorhus/p-limit",
+	"funding": "https://github.com/sponsors/sindresorhus",
+	"author": {
+		"name": "Sindre Sorhus",
+		"email": "sindresorhus@gmail.com",
+		"url": "https://sindresorhus.com"
+	},
+	"engines": {
+		"node": ">=10"
+	},
+	"scripts": {
+		"test": "xo && ava && tsd"
+	},
+	"files": [
+		"index.js",
+		"index.d.ts"
+	],
+	"keywords": [
+		"promise",
+		"limit",
+		"limited",
+		"concurrency",
+		"throttle",
+		"throat",
+		"rate",
+		"batch",
+		"ratelimit",
+		"task",
+		"queue",
+		"async",
+		"await",
+		"promises",
+		"bluebird"
+	],
+	"dependencies": {
+		"yocto-queue": "^0.1.0"
+	},
+	"devDependencies": {
+		"ava": "^2.4.0",
+		"delay": "^4.4.0",
+		"in-range": "^2.0.0",
+		"random-int": "^2.0.1",
+		"time-span": "^4.0.0",
+		"tsd": "^0.13.1",
+		"xo": "^0.35.0"
+	}
+}
Index: frontend/node_modules/react-dev-utils/node_modules/p-limit/readme.md
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-limit/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-limit/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,101 @@
+# p-limit
+
+> Run multiple promise-returning & async functions with limited concurrency
+
+## Install
+
+```
+$ npm install p-limit
+```
+
+## Usage
+
+```js
+const pLimit = require('p-limit');
+
+const limit = pLimit(1);
+
+const input = [
+	limit(() => fetchSomething('foo')),
+	limit(() => fetchSomething('bar')),
+	limit(() => doSomething())
+];
+
+(async () => {
+	// Only one promise is run at once
+	const result = await Promise.all(input);
+	console.log(result);
+})();
+```
+
+## API
+
+### pLimit(concurrency)
+
+Returns a `limit` function.
+
+#### concurrency
+
+Type: `number`\
+Minimum: `1`\
+Default: `Infinity`
+
+Concurrency limit.
+
+### limit(fn, ...args)
+
+Returns the promise returned by calling `fn(...args)`.
+
+#### fn
+
+Type: `Function`
+
+Promise-returning/async function.
+
+#### args
+
+Any arguments to pass through to `fn`.
+
+Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a *lot* of functions.
+
+### limit.activeCount
+
+The number of promises that are currently running.
+
+### limit.pendingCount
+
+The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
+
+### limit.clearQueue()
+
+Discard pending promises that are waiting to run.
+
+This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
+
+Note: This does not cancel promises that are already running.
+
+## FAQ
+
+### How is this different from the [`p-queue`](https://github.com/sindresorhus/p-queue) package?
+
+This package is only about limiting the number of concurrent executions, while `p-queue` is a fully featured queue implementation with lots of different options, introspection, and ability to pause the queue.
+
+## Related
+
+- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control
+- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
+- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
+- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
+- [More…](https://github.com/sindresorhus/promise-fun)
+
+---
+
+<div align="center">
+	<b>
+		<a href="https://tidelift.com/subscription/pkg/npm-p-limit?utm_source=npm-p-limit&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
+	</b>
+	<br>
+	<sub>
+		Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
+	</sub>
+</div>
Index: frontend/node_modules/react-dev-utils/node_modules/p-locate/index.d.ts
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-locate/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-locate/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,53 @@
+declare namespace pLocate {
+	interface Options {
+		/**
+		Number of concurrently pending promises returned by `tester`. Minimum: `1`.
+
+		@default Infinity
+		*/
+		readonly concurrency?: number;
+
+		/**
+		Preserve `input` order when searching.
+
+		Disable this to improve performance if you don't care about the order.
+
+		@default true
+		*/
+		readonly preserveOrder?: boolean;
+	}
+}
+
+/**
+Get the first fulfilled promise that satisfies the provided testing function.
+
+@param input - An iterable of promises/values to test.
+@param tester - This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.
+@returns A `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.
+
+@example
+```
+import pathExists = require('path-exists');
+import pLocate = require('p-locate');
+
+const files = [
+	'unicorn.png',
+	'rainbow.png', // Only this one actually exists on disk
+	'pony.png'
+];
+
+(async () => {
+	const foundPath = await pLocate(files, file => pathExists(file));
+
+	console.log(foundPath);
+	//=> 'rainbow'
+})();
+```
+*/
+declare function pLocate<ValueType>(
+	input: Iterable<PromiseLike<ValueType> | ValueType>,
+	tester: (element: ValueType) => PromiseLike<boolean> | boolean,
+	options?: pLocate.Options
+): Promise<ValueType | undefined>;
+
+export = pLocate;
Index: frontend/node_modules/react-dev-utils/node_modules/p-locate/index.js
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-locate/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-locate/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+'use strict';
+const pLimit = require('p-limit');
+
+class EndError extends Error {
+	constructor(value) {
+		super();
+		this.value = value;
+	}
+}
+
+// The input can also be a promise, so we await it
+const testElement = async (element, tester) => tester(await element);
+
+// The input can also be a promise, so we `Promise.all()` them both
+const finder = async element => {
+	const values = await Promise.all(element);
+	if (values[1] === true) {
+		throw new EndError(values[0]);
+	}
+
+	return false;
+};
+
+const pLocate = async (iterable, tester, options) => {
+	options = {
+		concurrency: Infinity,
+		preserveOrder: true,
+		...options
+	};
+
+	const limit = pLimit(options.concurrency);
+
+	// Start all the promises concurrently with optional limit
+	const items = [...iterable].map(element => [element, limit(testElement, element, tester)]);
+
+	// Check the promises either serially or concurrently
+	const checkLimit = pLimit(options.preserveOrder ? 1 : Infinity);
+
+	try {
+		await Promise.all(items.map(element => checkLimit(finder, element)));
+	} catch (error) {
+		if (error instanceof EndError) {
+			return error.value;
+		}
+
+		throw error;
+	}
+};
+
+module.exports = pLocate;
Index: frontend/node_modules/react-dev-utils/node_modules/p-locate/license
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-locate/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-locate/license	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: frontend/node_modules/react-dev-utils/node_modules/p-locate/package.json
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-locate/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-locate/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+{
+	"name": "p-locate",
+	"version": "5.0.0",
+	"description": "Get the first fulfilled promise that satisfies the provided testing function",
+	"license": "MIT",
+	"repository": "sindresorhus/p-locate",
+	"funding": "https://github.com/sponsors/sindresorhus",
+	"author": {
+		"name": "Sindre Sorhus",
+		"email": "sindresorhus@gmail.com",
+		"url": "https://sindresorhus.com"
+	},
+	"engines": {
+		"node": ">=10"
+	},
+	"scripts": {
+		"test": "xo && ava && tsd"
+	},
+	"files": [
+		"index.js",
+		"index.d.ts"
+	],
+	"keywords": [
+		"promise",
+		"locate",
+		"find",
+		"finder",
+		"search",
+		"searcher",
+		"test",
+		"array",
+		"collection",
+		"iterable",
+		"iterator",
+		"race",
+		"fulfilled",
+		"fastest",
+		"async",
+		"await",
+		"promises",
+		"bluebird"
+	],
+	"dependencies": {
+		"p-limit": "^3.0.2"
+	},
+	"devDependencies": {
+		"ava": "^2.4.0",
+		"delay": "^4.1.0",
+		"in-range": "^2.0.0",
+		"time-span": "^4.0.0",
+		"tsd": "^0.13.1",
+		"xo": "^0.32.1"
+	}
+}
Index: frontend/node_modules/react-dev-utils/node_modules/p-locate/readme.md
===================================================================
--- frontend/node_modules/react-dev-utils/node_modules/p-locate/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/node_modules/p-locate/readme.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,93 @@
+# p-locate [![Build Status](https://travis-ci.com/sindresorhus/p-locate.svg?branch=master)](https://travis-ci.com/github/sindresorhus/p-locate)
+
+> Get the first fulfilled promise that satisfies the provided testing function
+
+Think of it like an async version of [`Array#find`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
+
+## Install
+
+```
+$ npm install p-locate
+```
+
+## Usage
+
+Here we find the first file that exists on disk, in array order.
+
+```js
+const pathExists = require('path-exists');
+const pLocate = require('p-locate');
+
+const files = [
+	'unicorn.png',
+	'rainbow.png', // Only this one actually exists on disk
+	'pony.png'
+];
+
+(async () => {
+	const foundPath = await pLocate(files, file => pathExists(file));
+
+	console.log(foundPath);
+	//=> 'rainbow'
+})();
+```
+
+*The above is just an example. Use [`locate-path`](https://github.com/sindresorhus/locate-path) if you need this.*
+
+## API
+
+### pLocate(input, tester, options?)
+
+Returns a `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.
+
+#### input
+
+Type: `Iterable<Promise | unknown>`
+
+An iterable of promises/values to test.
+
+#### tester(element)
+
+Type: `Function`
+
+This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.
+
+#### options
+
+Type: `object`
+
+##### concurrency
+
+Type: `number`\
+Default: `Infinity`\
+Minimum: `1`
+
+Number of concurrently pending promises returned by `tester`.
+
+##### preserveOrder
+
+Type: `boolean`\
+Default: `true`
+
+Preserve `input` order when searching.
+
+Disable this to improve performance if you don't care about the order.
+
+## Related
+
+- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently
+- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently
+- [p-any](https://github.com/sindresorhus/p-any) - Wait for any promise to be fulfilled
+- [More…](https://github.com/sindresorhus/promise-fun)
+
+---
+
+<div align="center">
+	<b>
+		<a href="https://tidelift.com/subscription/pkg/npm-p-locate?utm_source=npm-p-locate&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
+	</b>
+	<br>
+	<sub>
+		Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
+	</sub>
+</div>
Index: frontend/node_modules/react-dev-utils/noopServiceWorkerMiddleware.js
===================================================================
--- frontend/node_modules/react-dev-utils/noopServiceWorkerMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/noopServiceWorkerMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const path = require('path');
+
+module.exports = function createNoopServiceWorkerMiddleware(servedPath) {
+  return function noopServiceWorkerMiddleware(req, res, next) {
+    if (req.url === path.posix.join(servedPath, 'service-worker.js')) {
+      res.setHeader('Content-Type', 'text/javascript');
+      res.send(
+        `// This service worker file is effectively a 'no-op' that will reset any
+// previous service worker registered for the same host:port combination.
+// In the production build, this file is replaced with an actual service worker
+// file that will precache your site's local assets.
+// See https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
+
+self.addEventListener('install', () => self.skipWaiting());
+
+self.addEventListener('activate', () => {
+  self.clients.matchAll({ type: 'window' }).then(windowClients => {
+    for (let windowClient of windowClients) {
+      // Force open pages to refresh, so that they have a chance to load the
+      // fresh navigation response from the local dev server.
+      windowClient.navigate(windowClient.url);
+    }
+  });
+});
+`
+      );
+    } else {
+      next();
+    }
+  };
+};
Index: frontend/node_modules/react-dev-utils/openBrowser.js
===================================================================
--- frontend/node_modules/react-dev-utils/openBrowser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/openBrowser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+var chalk = require('chalk');
+var execSync = require('child_process').execSync;
+var spawn = require('cross-spawn');
+var open = require('open');
+
+// https://github.com/sindresorhus/open#app
+var OSX_CHROME = 'google chrome';
+
+const Actions = Object.freeze({
+  NONE: 0,
+  BROWSER: 1,
+  SCRIPT: 2,
+});
+
+function getBrowserEnv() {
+  // Attempt to honor this environment variable.
+  // It is specific to the operating system.
+  // See https://github.com/sindresorhus/open#app for documentation.
+  const value = process.env.BROWSER;
+  const args = process.env.BROWSER_ARGS
+    ? process.env.BROWSER_ARGS.split(' ')
+    : [];
+  let action;
+  if (!value) {
+    // Default.
+    action = Actions.BROWSER;
+  } else if (value.toLowerCase().endsWith('.js')) {
+    action = Actions.SCRIPT;
+  } else if (value.toLowerCase() === 'none') {
+    action = Actions.NONE;
+  } else {
+    action = Actions.BROWSER;
+  }
+  return { action, value, args };
+}
+
+function executeNodeScript(scriptPath, url) {
+  const extraArgs = process.argv.slice(2);
+  const child = spawn(process.execPath, [scriptPath, ...extraArgs, url], {
+    stdio: 'inherit',
+  });
+  child.on('close', code => {
+    if (code !== 0) {
+      console.log();
+      console.log(
+        chalk.red(
+          'The script specified as BROWSER environment variable failed.'
+        )
+      );
+      console.log(chalk.cyan(scriptPath) + ' exited with code ' + code + '.');
+      console.log();
+      return;
+    }
+  });
+  return true;
+}
+
+function startBrowserProcess(browser, url, args) {
+  // If we're on OS X, the user hasn't specifically
+  // requested a different browser, we can try opening
+  // Chrome with AppleScript. This lets us reuse an
+  // existing tab when possible instead of creating a new one.
+  const shouldTryOpenChromiumWithAppleScript =
+    process.platform === 'darwin' &&
+    (typeof browser !== 'string' || browser === OSX_CHROME);
+
+  if (shouldTryOpenChromiumWithAppleScript) {
+    // Will use the first open browser found from list
+    const supportedChromiumBrowsers = [
+      'Google Chrome Canary',
+      'Google Chrome',
+      'Microsoft Edge',
+      'Brave Browser',
+      'Vivaldi',
+      'Chromium',
+    ];
+
+    for (let chromiumBrowser of supportedChromiumBrowsers) {
+      try {
+        // Try our best to reuse existing tab
+        // on OSX Chromium-based browser with AppleScript
+        execSync('ps cax | grep "' + chromiumBrowser + '"');
+        execSync(
+          'osascript openChrome.applescript "' +
+            encodeURI(url) +
+            '" "' +
+            chromiumBrowser +
+            '"',
+          {
+            cwd: __dirname,
+            stdio: 'ignore',
+          }
+        );
+        return true;
+      } catch (err) {
+        // Ignore errors.
+      }
+    }
+  }
+
+  // Another special case: on OS X, check if BROWSER has been set to "open".
+  // In this case, instead of passing `open` to `opn` (which won't work),
+  // just ignore it (thus ensuring the intended behavior, i.e. opening the system browser):
+  // https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768
+  if (process.platform === 'darwin' && browser === 'open') {
+    browser = undefined;
+  }
+
+  // If there are arguments, they must be passed as array with the browser
+  if (typeof browser === 'string' && args.length > 0) {
+    browser = [browser].concat(args);
+  }
+
+  // Fallback to open
+  // (It will always open new tab)
+  try {
+    var options = { app: browser, wait: false, url: true };
+    open(url, options).catch(() => {}); // Prevent `unhandledRejection` error.
+    return true;
+  } catch (err) {
+    return false;
+  }
+}
+
+/**
+ * Reads the BROWSER environment variable and decides what to do with it. Returns
+ * true if it opened a browser or ran a node.js script, otherwise false.
+ */
+function openBrowser(url) {
+  const { action, value, args } = getBrowserEnv();
+  switch (action) {
+    case Actions.NONE:
+      // Special case: BROWSER="none" will prevent opening completely.
+      return false;
+    case Actions.SCRIPT:
+      return executeNodeScript(value, url);
+    case Actions.BROWSER:
+      return startBrowserProcess(value, url, args);
+    default:
+      throw new Error('Not implemented.');
+  }
+}
+
+module.exports = openBrowser;
Index: frontend/node_modules/react-dev-utils/openChrome.applescript
===================================================================
--- frontend/node_modules/react-dev-utils/openChrome.applescript	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/openChrome.applescript	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,94 @@
+(*
+Copyright (c) 2015-present, Facebook, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*)
+
+property targetTab: null
+property targetTabIndex: -1
+property targetWindow: null
+property theProgram: "Google Chrome"
+
+on run argv
+  set theURL to item 1 of argv
+
+  -- Allow requested program to be optional,
+  -- default to Google Chrome
+  if (count of argv) > 1 then
+    set theProgram to item 2 of argv
+  end if
+
+  using terms from application "Google Chrome"
+    tell application theProgram
+
+      if (count every window) = 0 then
+        make new window
+      end if
+
+      -- 1: Looking for tab running debugger
+      -- then, Reload debugging tab if found
+      -- then return
+      set found to my lookupTabWithUrl(theURL)
+      if found then
+        set targetWindow's active tab index to targetTabIndex
+        tell targetTab to reload
+        tell targetWindow to activate
+        set index of targetWindow to 1
+        return
+      end if
+
+      -- 2: Looking for Empty tab
+      -- In case debugging tab was not found
+      -- We try to find an empty tab instead
+      set found to my lookupTabWithUrl("chrome://newtab/")
+      if found then
+        set targetWindow's active tab index to targetTabIndex
+        set URL of targetTab to theURL
+        tell targetWindow to activate
+        return
+      end if
+
+      -- 3: Create new tab
+      -- both debugging and empty tab were not found
+      -- make a new tab with url
+      tell window 1
+        activate
+        make new tab with properties {URL:theURL}
+      end tell
+    end tell
+  end using terms from
+end run
+
+-- Function:
+-- Lookup tab with given url
+-- if found, store tab, index, and window in properties
+-- (properties were declared on top of file)
+on lookupTabWithUrl(lookupUrl)
+  using terms from application "Google Chrome"
+    tell application theProgram
+      -- Find a tab with the given url
+      set found to false
+      set theTabIndex to -1
+      repeat with theWindow in every window
+        set theTabIndex to 0
+        repeat with theTab in every tab of theWindow
+          set theTabIndex to theTabIndex + 1
+          if (theTab's URL as string) contains lookupUrl then
+            -- assign tab, tab index, and window to properties
+            set targetTab to theTab
+            set targetTabIndex to theTabIndex
+            set targetWindow to theWindow
+            set found to true
+            exit repeat
+          end if
+        end repeat
+
+        if found then
+          exit repeat
+        end if
+      end repeat
+    end tell
+  end using terms from
+  return found
+end lookupTabWithUrl
Index: frontend/node_modules/react-dev-utils/package.json
===================================================================
--- frontend/node_modules/react-dev-utils/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+{
+  "name": "react-dev-utils",
+  "version": "12.0.1",
+  "description": "webpack utilities used by Create React App",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/facebook/create-react-app.git",
+    "directory": "packages/react-dev-utils"
+  },
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/facebook/create-react-app/issues"
+  },
+  "engines": {
+    "node": ">=14"
+  },
+  "files": [
+    "browsersHelper.js",
+    "chalk.js",
+    "checkRequiredFiles.js",
+    "clearConsole.js",
+    "crossSpawn.js",
+    "errorOverlayMiddleware.js",
+    "eslintFormatter.js",
+    "evalSourceMapMiddleware.js",
+    "FileSizeReporter.js",
+    "ForkTsCheckerWebpackPlugin.js",
+    "ForkTsCheckerWarningWebpackPlugin.js",
+    "formatWebpackMessages.js",
+    "getCacheIdentifier.js",
+    "getCSSModuleLocalIdent.js",
+    "getProcessForPort.js",
+    "getPublicUrlOrPath.js",
+    "globby.js",
+    "ignoredFiles.js",
+    "immer.js",
+    "InlineChunkHtmlPlugin.js",
+    "InterpolateHtmlPlugin.js",
+    "launchEditor.js",
+    "launchEditorEndpoint.js",
+    "ModuleNotFoundPlugin.js",
+    "ModuleScopePlugin.js",
+    "noopServiceWorkerMiddleware.js",
+    "openBrowser.js",
+    "openChrome.applescript",
+    "printBuildError.js",
+    "printHostingInstructions.js",
+    "redirectServedPathMiddleware.js",
+    "refreshOverlayInterop.js",
+    "typescriptFormatter.js",
+    "WebpackDevServerUtils.js",
+    "webpackHotDevClient.js"
+  ],
+  "dependencies": {
+    "@babel/code-frame": "^7.16.0",
+    "address": "^1.1.2",
+    "browserslist": "^4.18.1",
+    "chalk": "^4.1.2",
+    "cross-spawn": "^7.0.3",
+    "detect-port-alt": "^1.1.6",
+    "escape-string-regexp": "^4.0.0",
+    "filesize": "^8.0.6",
+    "find-up": "^5.0.0",
+    "fork-ts-checker-webpack-plugin": "^6.5.0",
+    "global-modules": "^2.0.0",
+    "globby": "^11.0.4",
+    "gzip-size": "^6.0.0",
+    "immer": "^9.0.7",
+    "is-root": "^2.1.0",
+    "loader-utils": "^3.2.0",
+    "open": "^8.4.0",
+    "pkg-up": "^3.1.0",
+    "prompts": "^2.4.2",
+    "react-error-overlay": "^6.0.11",
+    "recursive-readdir": "^2.2.2",
+    "shell-quote": "^1.7.3",
+    "strip-ansi": "^6.0.1",
+    "text-table": "^0.2.0"
+  },
+  "devDependencies": {
+    "cross-env": "^7.0.3",
+    "jest": "^27.4.3"
+  },
+  "scripts": {
+    "test": "cross-env FORCE_COLOR=true jest"
+  },
+  "gitHead": "19fa58d527ae74f2b6baa0867463eea1d290f9a5"
+}
Index: frontend/node_modules/react-dev-utils/printBuildError.js
===================================================================
--- frontend/node_modules/react-dev-utils/printBuildError.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/printBuildError.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const chalk = require('chalk');
+
+module.exports = function printBuildError(err) {
+  const message = err != null && err.message;
+  const stack = err != null && err.stack;
+
+  // Add more helpful message for Terser error
+  if (
+    stack &&
+    typeof message === 'string' &&
+    message.indexOf('from Terser') !== -1
+  ) {
+    try {
+      const matched = /(.+)\[(.+):(.+),(.+)\]\[.+\]/.exec(stack);
+      if (!matched) {
+        throw new Error('Using errors for control flow is bad.');
+      }
+      const problemPath = matched[2];
+      const line = matched[3];
+      const column = matched[4];
+      console.log(
+        'Failed to minify the code from this file: \n\n',
+        chalk.yellow(
+          `\t${problemPath}:${line}${column !== '0' ? ':' + column : ''}`
+        ),
+        '\n'
+      );
+    } catch (ignored) {
+      console.log('Failed to minify the bundle.', err);
+    }
+    console.log('Read more here: https://cra.link/failed-to-minify');
+  } else {
+    console.log((message || err) + '\n');
+  }
+  console.log();
+};
Index: frontend/node_modules/react-dev-utils/printHostingInstructions.js
===================================================================
--- frontend/node_modules/react-dev-utils/printHostingInstructions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/printHostingInstructions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+const chalk = require('chalk');
+const url = require('url');
+const globalModules = require('global-modules');
+const fs = require('fs');
+
+function printHostingInstructions(
+  appPackage,
+  publicUrl,
+  publicPath,
+  buildFolder,
+  useYarn
+) {
+  if (publicUrl && publicUrl.includes('.github.io/')) {
+    // "homepage": "http://user.github.io/project"
+    const publicPathname = url.parse(publicPath).pathname;
+    const hasDeployScript =
+      typeof appPackage.scripts !== 'undefined' &&
+      typeof appPackage.scripts.deploy !== 'undefined';
+    printBaseMessage(buildFolder, publicPathname);
+
+    printDeployInstructions(publicUrl, hasDeployScript, useYarn);
+  } else if (publicPath !== '/') {
+    // "homepage": "http://mywebsite.com/project"
+    printBaseMessage(buildFolder, publicPath);
+  } else {
+    // "homepage": "http://mywebsite.com"
+    //   or no homepage
+    printBaseMessage(buildFolder, publicUrl);
+
+    printStaticServerInstructions(buildFolder, useYarn);
+  }
+  console.log();
+  console.log('Find out more about deployment here:');
+  console.log();
+  console.log(`  ${chalk.yellow('https://cra.link/deployment')}`);
+  console.log();
+}
+
+function printBaseMessage(buildFolder, hostingLocation) {
+  console.log(
+    `The project was built assuming it is hosted at ${chalk.green(
+      hostingLocation || 'the server root'
+    )}.`
+  );
+  console.log(
+    `You can control this with the ${chalk.green(
+      'homepage'
+    )} field in your ${chalk.cyan('package.json')}.`
+  );
+
+  if (!hostingLocation) {
+    console.log('For example, add this to build it for GitHub Pages:');
+    console.log();
+
+    console.log(
+      `  ${chalk.green('"homepage"')} ${chalk.cyan(':')} ${chalk.green(
+        '"http://myname.github.io/myapp"'
+      )}${chalk.cyan(',')}`
+    );
+  }
+  console.log();
+  console.log(`The ${chalk.cyan(buildFolder)} folder is ready to be deployed.`);
+}
+
+function printDeployInstructions(publicUrl, hasDeployScript, useYarn) {
+  console.log(`To publish it at ${chalk.green(publicUrl)} , run:`);
+  console.log();
+
+  // If script deploy has been added to package.json, skip the instructions
+  if (!hasDeployScript) {
+    if (useYarn) {
+      console.log(`  ${chalk.cyan('yarn')} add --dev gh-pages`);
+    } else {
+      console.log(`  ${chalk.cyan('npm')} install --save-dev gh-pages`);
+    }
+    console.log();
+
+    console.log(
+      `Add the following script in your ${chalk.cyan('package.json')}.`
+    );
+    console.log();
+
+    console.log(`    ${chalk.dim('// ...')}`);
+    console.log(`    ${chalk.yellow('"scripts"')}: {`);
+    console.log(`      ${chalk.dim('// ...')}`);
+    console.log(
+      `      ${chalk.yellow('"predeploy"')}: ${chalk.yellow(
+        `"${useYarn ? 'yarn' : 'npm run'} build",`
+      )}`
+    );
+    console.log(
+      `      ${chalk.yellow('"deploy"')}: ${chalk.yellow(
+        '"gh-pages -d build"'
+      )}`
+    );
+    console.log('    }');
+    console.log();
+
+    console.log('Then run:');
+    console.log();
+  }
+  console.log(`  ${chalk.cyan(useYarn ? 'yarn' : 'npm')} run deploy`);
+}
+
+function printStaticServerInstructions(buildFolder, useYarn) {
+  console.log('You may serve it with a static server:');
+  console.log();
+
+  if (!fs.existsSync(`${globalModules}/serve`)) {
+    if (useYarn) {
+      console.log(`  ${chalk.cyan('yarn')} global add serve`);
+    } else {
+      console.log(`  ${chalk.cyan('npm')} install -g serve`);
+    }
+  }
+  console.log(`  ${chalk.cyan('serve')} -s ${buildFolder}`);
+}
+
+module.exports = printHostingInstructions;
Index: frontend/node_modules/react-dev-utils/redirectServedPathMiddleware.js
===================================================================
--- frontend/node_modules/react-dev-utils/redirectServedPathMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/redirectServedPathMiddleware.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+'use strict';
+
+const path = require('path');
+
+module.exports = function createRedirectServedPathMiddleware(servedPath) {
+  // remove end slash so user can land on `/test` instead of `/test/`
+  servedPath = servedPath.slice(0, -1);
+  return function redirectServedPathMiddleware(req, res, next) {
+    if (
+      servedPath === '' ||
+      req.url === servedPath ||
+      req.url.startsWith(servedPath)
+    ) {
+      next();
+    } else {
+      const newPath = path.posix.join(servedPath, req.path !== '/' ? req.path : '');
+      res.redirect(newPath);
+    }
+  };
+};
Index: frontend/node_modules/react-dev-utils/refreshOverlayInterop.js
===================================================================
--- frontend/node_modules/react-dev-utils/refreshOverlayInterop.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/refreshOverlayInterop.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,19 @@
+// @remove-on-eject-begin
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+// @remove-on-eject-end
+'use strict';
+
+const {
+  dismissRuntimeErrors,
+  reportRuntimeError,
+} = require('react-error-overlay');
+
+module.exports = {
+  clearRuntimeErrors: dismissRuntimeErrors,
+  handleRuntimeError: reportRuntimeError,
+};
Index: frontend/node_modules/react-dev-utils/webpackHotDevClient.js
===================================================================
--- frontend/node_modules/react-dev-utils/webpackHotDevClient.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/react-dev-utils/webpackHotDevClient.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,294 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+'use strict';
+
+// This alternative WebpackDevServer combines the functionality of:
+// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
+// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js
+
+// It only supports their simplest configuration (hot updates on same server).
+// It makes some opinionated choices on top, like adding a syntax error overlay
+// that looks similar to our console output. The error overlay is inspired by:
+// https://github.com/glenjamin/webpack-hot-middleware
+
+var stripAnsi = require('strip-ansi');
+var url = require('url');
+var launchEditorEndpoint = require('./launchEditorEndpoint');
+var formatWebpackMessages = require('./formatWebpackMessages');
+var ErrorOverlay = require('react-error-overlay');
+
+ErrorOverlay.setEditorHandler(function editorHandler(errorLocation) {
+  // Keep this sync with errorOverlayMiddleware.js
+  fetch(
+    launchEditorEndpoint +
+      '?fileName=' +
+      window.encodeURIComponent(errorLocation.fileName) +
+      '&lineNumber=' +
+      window.encodeURIComponent(errorLocation.lineNumber || 1) +
+      '&colNumber=' +
+      window.encodeURIComponent(errorLocation.colNumber || 1)
+  );
+});
+
+// We need to keep track of if there has been a runtime error.
+// Essentially, we cannot guarantee application state was not corrupted by the
+// runtime error. To prevent confusing behavior, we forcibly reload the entire
+// application. This is handled below when we are notified of a compile (code
+// change).
+// See https://github.com/facebook/create-react-app/issues/3096
+var hadRuntimeError = false;
+ErrorOverlay.startReportingRuntimeErrors({
+  onError: function () {
+    hadRuntimeError = true;
+  },
+  filename: '/static/js/bundle.js',
+});
+
+if (module.hot && typeof module.hot.dispose === 'function') {
+  module.hot.dispose(function () {
+    // TODO: why do we need this?
+    ErrorOverlay.stopReportingRuntimeErrors();
+  });
+}
+
+// Connect to WebpackDevServer via a socket.
+var connection = new WebSocket(
+  url.format({
+    protocol: window.location.protocol === 'https:' ? 'wss' : 'ws',
+    hostname: process.env.WDS_SOCKET_HOST || window.location.hostname,
+    port: process.env.WDS_SOCKET_PORT || window.location.port,
+    // Hardcoded in WebpackDevServer
+    pathname: process.env.WDS_SOCKET_PATH || '/ws',
+    slashes: true,
+  })
+);
+
+// Unlike WebpackDevServer client, we won't try to reconnect
+// to avoid spamming the console. Disconnect usually happens
+// when developer stops the server.
+connection.onclose = function () {
+  if (typeof console !== 'undefined' && typeof console.info === 'function') {
+    console.info(
+      'The development server has disconnected.\nRefresh the page if necessary.'
+    );
+  }
+};
+
+// Remember some state related to hot module replacement.
+var isFirstCompilation = true;
+var mostRecentCompilationHash = null;
+var hasCompileErrors = false;
+
+function clearOutdatedErrors() {
+  // Clean up outdated compile errors, if any.
+  if (typeof console !== 'undefined' && typeof console.clear === 'function') {
+    if (hasCompileErrors) {
+      console.clear();
+    }
+  }
+}
+
+// Successful compilation.
+function handleSuccess() {
+  clearOutdatedErrors();
+
+  var isHotUpdate = !isFirstCompilation;
+  isFirstCompilation = false;
+  hasCompileErrors = false;
+
+  // Attempt to apply hot updates or reload.
+  if (isHotUpdate) {
+    tryApplyUpdates(function onHotUpdateSuccess() {
+      // Only dismiss it when we're sure it's a hot update.
+      // Otherwise it would flicker right before the reload.
+      tryDismissErrorOverlay();
+    });
+  }
+}
+
+// Compilation with warnings (e.g. ESLint).
+function handleWarnings(warnings) {
+  clearOutdatedErrors();
+
+  var isHotUpdate = !isFirstCompilation;
+  isFirstCompilation = false;
+  hasCompileErrors = false;
+
+  function printWarnings() {
+    // Print warnings to the console.
+    var formatted = formatWebpackMessages({
+      warnings: warnings,
+      errors: [],
+    });
+
+    if (typeof console !== 'undefined' && typeof console.warn === 'function') {
+      for (var i = 0; i < formatted.warnings.length; i++) {
+        if (i === 5) {
+          console.warn(
+            'There were more warnings in other files.\n' +
+              'You can find a complete log in the terminal.'
+          );
+          break;
+        }
+        console.warn(stripAnsi(formatted.warnings[i]));
+      }
+    }
+  }
+
+  printWarnings();
+
+  // Attempt to apply hot updates or reload.
+  if (isHotUpdate) {
+    tryApplyUpdates(function onSuccessfulHotUpdate() {
+      // Only dismiss it when we're sure it's a hot update.
+      // Otherwise it would flicker right before the reload.
+      tryDismissErrorOverlay();
+    });
+  }
+}
+
+// Compilation with errors (e.g. syntax error or missing modules).
+function handleErrors(errors) {
+  clearOutdatedErrors();
+
+  isFirstCompilation = false;
+  hasCompileErrors = true;
+
+  // "Massage" webpack messages.
+  var formatted = formatWebpackMessages({
+    errors: errors,
+    warnings: [],
+  });
+
+  // Only show the first error.
+  ErrorOverlay.reportBuildError(formatted.errors[0]);
+
+  // Also log them to the console.
+  if (typeof console !== 'undefined' && typeof console.error === 'function') {
+    for (var i = 0; i < formatted.errors.length; i++) {
+      console.error(stripAnsi(formatted.errors[i]));
+    }
+  }
+
+  // Do not attempt to reload now.
+  // We will reload on next success instead.
+}
+
+function tryDismissErrorOverlay() {
+  if (!hasCompileErrors) {
+    ErrorOverlay.dismissBuildError();
+  }
+}
+
+// There is a newer version of the code available.
+function handleAvailableHash(hash) {
+  // Update last known compilation hash.
+  mostRecentCompilationHash = hash;
+}
+
+// Handle messages from the server.
+connection.onmessage = function (e) {
+  var message = JSON.parse(e.data);
+  switch (message.type) {
+    case 'hash':
+      handleAvailableHash(message.data);
+      break;
+    case 'still-ok':
+    case 'ok':
+      handleSuccess();
+      break;
+    case 'content-changed':
+      // Triggered when a file from `contentBase` changed.
+      window.location.reload();
+      break;
+    case 'warnings':
+      handleWarnings(message.data);
+      break;
+    case 'errors':
+      handleErrors(message.data);
+      break;
+    default:
+    // Do nothing.
+  }
+};
+
+// Is there a newer version of this code available?
+function isUpdateAvailable() {
+  /* globals __webpack_hash__ */
+  // __webpack_hash__ is the hash of the current compilation.
+  // It's a global variable injected by webpack.
+  return mostRecentCompilationHash !== __webpack_hash__;
+}
+
+// webpack disallows updates in other states.
+function canApplyUpdates() {
+  return module.hot.status() === 'idle';
+}
+
+function canAcceptErrors() {
+  // NOTE: This var is injected by Webpack's DefinePlugin, and is a boolean instead of string.
+  const hasReactRefresh = process.env.FAST_REFRESH;
+
+  const status = module.hot.status();
+  // React refresh can handle hot-reloading over errors.
+  // However, when hot-reload status is abort or fail,
+  // it indicates the current update cannot be applied safely,
+  // and thus we should bail out to a forced reload for consistency.
+  return hasReactRefresh && ['abort', 'fail'].indexOf(status) === -1;
+}
+
+// Attempt to update code on the fly, fall back to a hard reload.
+function tryApplyUpdates(onHotUpdateSuccess) {
+  if (!module.hot) {
+    // HotModuleReplacementPlugin is not in webpack configuration.
+    window.location.reload();
+    return;
+  }
+
+  if (!isUpdateAvailable() || !canApplyUpdates()) {
+    return;
+  }
+
+  function handleApplyUpdates(err, updatedModules) {
+    const haveErrors = err || hadRuntimeError;
+    // When there is no error but updatedModules is unavailable,
+    // it indicates a critical failure in hot-reloading,
+    // e.g. server is not ready to serve new bundle,
+    // and hence we need to do a forced reload.
+    const needsForcedReload = !err && !updatedModules;
+    if ((haveErrors && !canAcceptErrors()) || needsForcedReload) {
+      window.location.reload();
+      return;
+    }
+
+    if (typeof onHotUpdateSuccess === 'function') {
+      // Maybe we want to do something.
+      onHotUpdateSuccess();
+    }
+
+    if (isUpdateAvailable()) {
+      // While we were updating, there was a new update! Do it again.
+      tryApplyUpdates();
+    }
+  }
+
+  // https://webpack.github.io/docs/hot-module-replacement.html#check
+  var result = module.hot.check(/* autoApply */ true, handleApplyUpdates);
+
+  // // webpack 2 returns a Promise instead of invoking a callback
+  if (result && result.then) {
+    result.then(
+      function (updatedModules) {
+        handleApplyUpdates(null, updatedModules);
+      },
+      function (err) {
+        handleApplyUpdates(err, null);
+      }
+    );
+  }
+}
