Index: frontend/node_modules/eslint-webpack-plugin/dist/ESLintError.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/ESLintError.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/ESLintError.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+
+class ESLintError extends Error {
+  /**
+   * @param {string=} messages
+   */
+  constructor(messages) {
+    super(`[eslint] ${messages}`);
+    this.name = 'ESLintError';
+    this.stack = '';
+  }
+
+}
+
+module.exports = ESLintError;
Index: frontend/node_modules/eslint-webpack-plugin/dist/getESLint.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/getESLint.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/getESLint.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,160 @@
+"use strict";
+
+const {
+  cpus
+} = require('os');
+
+const {
+  Worker: JestWorker
+} = require('jest-worker');
+
+const {
+  getESLintOptions
+} = require('./options');
+
+const {
+  jsonStringifyReplacerSortKeys
+} = require('./utils');
+/** @type {{[key: string]: any}} */
+
+
+const cache = {};
+/** @typedef {import('eslint').ESLint} ESLint */
+
+/** @typedef {import('eslint').ESLint.LintResult} LintResult */
+
+/** @typedef {import('./options').Options} Options */
+
+/** @typedef {() => Promise<void>} AsyncTask */
+
+/** @typedef {(files: string|string[]) => Promise<LintResult[]>} LintTask */
+
+/** @typedef {{threads: number, ESLint: ESLint, eslint: ESLint, lintFiles: LintTask, cleanup: AsyncTask}} Linter */
+
+/** @typedef {JestWorker & {lintFiles: LintTask}} Worker */
+
+/**
+ * @param {Options} options
+ * @returns {Linter}
+ */
+
+function loadESLint(options) {
+  const {
+    eslintPath
+  } = options;
+
+  const {
+    ESLint
+  } = require(eslintPath || 'eslint'); // Filter out loader options before passing the options to ESLint.
+
+
+  const eslint = new ESLint(getESLintOptions(options));
+  return {
+    threads: 1,
+    ESLint,
+    eslint,
+    lintFiles: async files => {
+      const results = await eslint.lintFiles(files); // istanbul ignore else
+
+      if (options.fix) {
+        await ESLint.outputFixes(results);
+      }
+
+      return results;
+    },
+    // no-op for non-threaded
+    cleanup: async () => {}
+  };
+}
+/**
+ * @param {string|undefined} key
+ * @param {number} poolSize
+ * @param {Options} options
+ * @returns {Linter}
+ */
+
+
+function loadESLintThreaded(key, poolSize, options) {
+  const cacheKey = getCacheKey(key, options);
+  const {
+    eslintPath = 'eslint'
+  } = options;
+
+  const source = require.resolve('./worker');
+
+  const workerOptions = {
+    enableWorkerThreads: true,
+    numWorkers: poolSize,
+    setupArgs: [{
+      eslintPath,
+      eslintOptions: getESLintOptions(options)
+    }]
+  };
+  const local = loadESLint(options);
+  let worker =
+  /** @type {Worker?} */
+  new JestWorker(source, workerOptions);
+  /** @type {Linter} */
+
+  const context = { ...local,
+    threads: poolSize,
+    lintFiles: async files => worker && (await worker.lintFiles(files)) ||
+    /* istanbul ignore next */
+    [],
+    cleanup: async () => {
+      cache[cacheKey] = local;
+
+      context.lintFiles = files => local.lintFiles(files);
+
+      if (worker) {
+        worker.end();
+        worker = null;
+      }
+    }
+  };
+  return context;
+}
+/**
+ * @param {string|undefined} key
+ * @param {Options} options
+ * @returns {Linter}
+ */
+
+
+function getESLint(key, {
+  threads,
+  ...options
+}) {
+  const max = typeof threads !== 'number' ? threads ? cpus().length - 1 : 1 :
+  /* istanbul ignore next */
+  threads;
+  const cacheKey = getCacheKey(key, {
+    threads,
+    ...options
+  });
+
+  if (!cache[cacheKey]) {
+    cache[cacheKey] = max > 1 ? loadESLintThreaded(key, max, options) : loadESLint(options);
+  }
+
+  return cache[cacheKey];
+}
+/**
+ * @param {string|undefined} key
+ * @param {Options} options
+ * @returns {string}
+ */
+
+
+function getCacheKey(key, options) {
+  return JSON.stringify({
+    key,
+    options
+  }, jsonStringifyReplacerSortKeys);
+}
+
+module.exports = {
+  loadESLint,
+  loadESLintThreaded,
+  getESLint
+};
Index: frontend/node_modules/eslint-webpack-plugin/dist/index.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,195 @@
+"use strict";
+
+const {
+  isAbsolute,
+  join
+} = require('path');
+
+const {
+  isMatch
+} = require('micromatch');
+
+const {
+  getOptions
+} = require('./options');
+
+const linter = require('./linter');
+
+const {
+  arrify,
+  parseFiles,
+  parseFoldersToGlobs
+} = require('./utils');
+/** @typedef {import('webpack').Compiler} Compiler */
+
+/** @typedef {import('./options').Options} Options */
+
+
+const ESLINT_PLUGIN = 'ESLintWebpackPlugin';
+let counter = 0;
+
+class ESLintWebpackPlugin {
+  /**
+   * @param {Options} options
+   */
+  constructor(options = {}) {
+    this.key = ESLINT_PLUGIN;
+    this.options = getOptions(options);
+    this.run = this.run.bind(this);
+  }
+  /**
+   * @param {Compiler} compiler
+   * @returns {void}
+   */
+
+
+  apply(compiler) {
+    // Generate key for each compilation,
+    // this differentiates one from the other when being cached.
+    this.key = compiler.name || `${this.key}_${counter += 1}`;
+    const options = { ...this.options,
+      exclude: parseFiles(this.options.exclude || [], this.getContext(compiler)),
+      extensions: arrify(this.options.extensions),
+      resourceQueryExclude: arrify(this.options.resourceQueryExclude || []).map(item => item instanceof RegExp ? item : new RegExp(item)),
+      files: parseFiles(this.options.files || '', this.getContext(compiler))
+    };
+    const wanted = parseFoldersToGlobs(options.files, options.extensions);
+    const exclude = parseFoldersToGlobs(this.options.exclude ? options.exclude : '**/node_modules/**', []); // If `lintDirtyModulesOnly` is disabled,
+    // execute the linter on the build
+
+    if (!this.options.lintDirtyModulesOnly) {
+      compiler.hooks.run.tapPromise(this.key, c => this.run(c, options, wanted, exclude));
+    }
+
+    let isFirstRun = this.options.lintDirtyModulesOnly;
+    compiler.hooks.watchRun.tapPromise(this.key, c => {
+      if (isFirstRun) {
+        isFirstRun = false;
+        return Promise.resolve();
+      }
+
+      return this.run(c, options, wanted, exclude);
+    });
+  }
+  /**
+   * @param {Compiler} compiler
+   * @param {Omit<Options, 'resourceQueryExclude'> & {resourceQueryExclude: RegExp[]}} options
+   * @param {string[]} wanted
+   * @param {string[]} exclude
+   */
+
+
+  async run(compiler, options, wanted, exclude) {
+    // Do not re-hook
+    if ( // @ts-ignore
+    compiler.hooks.compilation.taps.find(({
+      name
+    }) => name === this.key)) {
+      return;
+    }
+
+    compiler.hooks.compilation.tap(this.key, compilation => {
+      /** @type {import('./linter').Linter} */
+      let lint;
+      /** @type {import('./linter').Reporter} */
+
+      let report;
+      /** @type number */
+
+      let threads;
+
+      try {
+        ({
+          lint,
+          report,
+          threads
+        } = linter(this.key, options, compilation));
+      } catch (e) {
+        compilation.errors.push(e);
+        return;
+      }
+      /** @type {string[]} */
+
+
+      const files = []; // @ts-ignore
+      // Add the file to be linted
+
+      compilation.hooks.succeedModule.tap(this.key, ({
+        resource
+      }) => {
+        if (resource) {
+          const [file, query] = resource.split('?');
+
+          if (file && !files.includes(file) && isMatch(file, wanted, {
+            dot: true
+          }) && !isMatch(file, exclude, {
+            dot: true
+          }) && options.resourceQueryExclude.every(reg => !reg.test(query))) {
+            files.push(file);
+
+            if (threads > 1) {
+              lint(file);
+            }
+          }
+        }
+      }); // Lint all files added
+
+      compilation.hooks.finishModules.tap(this.key, () => {
+        if (files.length > 0 && threads <= 1) {
+          lint(files);
+        }
+      }); // await and interpret results
+
+      compilation.hooks.additionalAssets.tapPromise(this.key, processResults);
+
+      async function processResults() {
+        const {
+          errors,
+          warnings,
+          generateReportAsset
+        } = await report();
+
+        if (warnings && !options.failOnWarning) {
+          // @ts-ignore
+          compilation.warnings.push(warnings);
+        } else if (warnings && options.failOnWarning) {
+          // @ts-ignore
+          compilation.errors.push(warnings);
+        }
+
+        if (errors && options.failOnError) {
+          // @ts-ignore
+          compilation.errors.push(errors);
+        } else if (errors && !options.failOnError) {
+          // @ts-ignore
+          compilation.warnings.push(errors);
+        }
+
+        if (generateReportAsset) {
+          await generateReportAsset(compilation);
+        }
+      }
+    });
+  }
+  /**
+   *
+   * @param {Compiler} compiler
+   * @returns {string}
+   */
+
+
+  getContext(compiler) {
+    if (!this.options.context) {
+      return String(compiler.options.context);
+    }
+
+    if (!isAbsolute(this.options.context)) {
+      return join(String(compiler.options.context), this.options.context);
+    }
+
+    return this.options.context;
+  }
+
+}
+
+module.exports = ESLintWebpackPlugin;
Index: frontend/node_modules/eslint-webpack-plugin/dist/linter.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/linter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/linter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,342 @@
+"use strict";
+
+const {
+  dirname,
+  isAbsolute,
+  join
+} = require('path');
+
+const ESLintError = require('./ESLintError');
+
+const {
+  getESLint
+} = require('./getESLint');
+/** @typedef {import('eslint').ESLint} ESLint */
+
+/** @typedef {import('eslint').ESLint.Formatter} Formatter */
+
+/** @typedef {import('eslint').ESLint.LintResult} LintResult */
+
+/** @typedef {import('webpack').Compiler} Compiler */
+
+/** @typedef {import('webpack').Compilation} Compilation */
+
+/** @typedef {import('./options').Options} Options */
+
+/** @typedef {import('./options').FormatterFunction} FormatterFunction */
+
+/** @typedef {(compilation: Compilation) => Promise<void>} GenerateReport */
+
+/** @typedef {{errors?: ESLintError, warnings?: ESLintError, generateReportAsset?: GenerateReport}} Report */
+
+/** @typedef {() => Promise<Report>} Reporter */
+
+/** @typedef {(files: string|string[]) => void} Linter */
+
+/** @typedef {{[files: string]: LintResult}} LintResultMap */
+
+/** @type {WeakMap<Compiler, LintResultMap>} */
+
+
+const resultStorage = new WeakMap();
+/**
+ * @param {string|undefined} key
+ * @param {Options} options
+ * @param {Compilation} compilation
+ * @returns {{lint: Linter, report: Reporter, threads: number}}
+ */
+
+function linter(key, options, compilation) {
+  /** @type {ESLint} */
+  let eslint;
+  /** @type {(files: string|string[]) => Promise<LintResult[]>} */
+
+  let lintFiles;
+  /** @type {() => Promise<void>} */
+
+  let cleanup;
+  /** @type number */
+
+  let threads;
+  /** @type {Promise<LintResult[]>[]} */
+
+  const rawResults = [];
+  const crossRunResultStorage = getResultStorage(compilation);
+
+  try {
+    ({
+      eslint,
+      lintFiles,
+      cleanup,
+      threads
+    } = getESLint(key, options));
+  } catch (e) {
+    throw new ESLintError(e.message);
+  }
+
+  return {
+    lint,
+    report,
+    threads
+  };
+  /**
+   * @param {string | string[]} files
+   */
+
+  function lint(files) {
+    for (const file of asList(files)) {
+      delete crossRunResultStorage[file];
+    }
+
+    rawResults.push(lintFiles(files).catch(e => {
+      // @ts-ignore
+      compilation.errors.push(new ESLintError(e.message));
+      return [];
+    }));
+  }
+
+  async function report() {
+    // Filter out ignored files.
+    let results = await removeIgnoredWarnings(eslint, // Get the current results, resetting the rawResults to empty
+    await flatten(rawResults.splice(0, rawResults.length)));
+    await cleanup();
+
+    for (const result of results) {
+      crossRunResultStorage[result.filePath] = result;
+    }
+
+    results = Object.values(crossRunResultStorage); // do not analyze if there are no results or eslint config
+
+    if (!results || results.length < 1) {
+      return {};
+    }
+
+    const formatter = await loadFormatter(eslint, options.formatter);
+    const {
+      errors,
+      warnings
+    } = await formatResults(formatter, parseResults(options, results));
+    return {
+      errors,
+      warnings,
+      generateReportAsset
+    };
+    /**
+     * @param {Compilation} compilation
+     * @returns {Promise<void>}
+     */
+
+    async function generateReportAsset({
+      compiler
+    }) {
+      const {
+        outputReport
+      } = options;
+      /**
+       * @param {string} name
+       * @param {string | Buffer} content
+       */
+
+      const save = (name, content) =>
+      /** @type {Promise<void>} */
+      new Promise((finish, bail) => {
+        const {
+          mkdir,
+          writeFile
+        } = compiler.outputFileSystem; // ensure directory exists
+        // @ts-ignore - the types for `outputFileSystem` are missing the 3 arg overload
+
+        mkdir(dirname(name), {
+          recursive: true
+        }, err => {
+          /* istanbul ignore if */
+          if (err) bail(err);else writeFile(name, content, err2 => {
+            /* istanbul ignore if */
+            if (err2) bail(err2);else finish();
+          });
+        });
+      });
+
+      if (!outputReport || !outputReport.filePath) {
+        return;
+      }
+
+      const content = await (outputReport.formatter ? (await loadFormatter(eslint, outputReport.formatter)).format(results) : formatter.format(results));
+      let {
+        filePath
+      } = outputReport;
+
+      if (!isAbsolute(filePath)) {
+        filePath = join(compiler.outputPath, filePath);
+      }
+
+      await save(filePath, content);
+    }
+  }
+}
+/**
+ * @param {Formatter} formatter
+ * @param {{ errors: LintResult[]; warnings: LintResult[]; }} results
+ * @returns {Promise<{errors?: ESLintError, warnings?: ESLintError}>}
+ */
+
+
+async function formatResults(formatter, results) {
+  let errors;
+  let warnings;
+
+  if (results.warnings.length > 0) {
+    warnings = new ESLintError(await formatter.format(results.warnings));
+  }
+
+  if (results.errors.length > 0) {
+    errors = new ESLintError(await formatter.format(results.errors));
+  }
+
+  return {
+    errors,
+    warnings
+  };
+}
+/**
+ * @param {Options} options
+ * @param {LintResult[]} results
+ * @returns {{errors: LintResult[], warnings: LintResult[]}}
+ */
+
+
+function parseResults(options, results) {
+  /** @type {LintResult[]} */
+  const errors = [];
+  /** @type {LintResult[]} */
+
+  const warnings = [];
+  results.forEach(file => {
+    if (fileHasErrors(file)) {
+      const messages = file.messages.filter(message => options.emitError && message.severity === 2);
+
+      if (messages.length > 0) {
+        errors.push({ ...file,
+          messages
+        });
+      }
+    }
+
+    if (fileHasWarnings(file)) {
+      const messages = file.messages.filter(message => options.emitWarning && message.severity === 1);
+
+      if (messages.length > 0) {
+        warnings.push({ ...file,
+          messages
+        });
+      }
+    }
+  });
+  return {
+    errors,
+    warnings
+  };
+}
+/**
+ * @param {LintResult} file
+ * @returns {boolean}
+ */
+
+
+function fileHasErrors(file) {
+  return file.errorCount > 0;
+}
+/**
+ * @param {LintResult} file
+ * @returns {boolean}
+ */
+
+
+function fileHasWarnings(file) {
+  return file.warningCount > 0;
+}
+/**
+ * @param {ESLint} eslint
+ * @param {string|FormatterFunction=} formatter
+ * @returns {Promise<Formatter>}
+ */
+
+
+async function loadFormatter(eslint, formatter) {
+  if (typeof formatter === 'function') {
+    return {
+      format: formatter
+    };
+  }
+
+  if (typeof formatter === 'string') {
+    try {
+      return eslint.loadFormatter(formatter);
+    } catch (_) {// Load the default formatter.
+    }
+  }
+
+  return eslint.loadFormatter();
+}
+/**
+ * @param {ESLint} eslint
+ * @param {LintResult[]} results
+ * @returns {Promise<LintResult[]>}
+ */
+
+
+async function removeIgnoredWarnings(eslint, results) {
+  const filterPromises = results.map(async result => {
+    // Short circuit the call to isPathIgnored.
+    //   fatal is false for ignored file warnings.
+    //   ruleId is unset for internal ESLint errors.
+    //   line is unset for warnings not involving file contents.
+    const ignored = result.messages.length === 0 || result.warningCount === 1 && result.errorCount === 0 && !result.messages[0].fatal && !result.messages[0].ruleId && !result.messages[0].line && (await eslint.isPathIgnored(result.filePath));
+    return ignored ? false : result;
+  }); // @ts-ignore
+
+  return (await Promise.all(filterPromises)).filter(result => !!result);
+}
+/**
+ * @param {Promise<LintResult[]>[]} results
+ * @returns {Promise<LintResult[]>}
+ */
+
+
+async function flatten(results) {
+  /**
+   * @param {LintResult[]} acc
+   * @param {LintResult[]} list
+   */
+  const flat = (acc, list) => [...acc, ...list];
+
+  return (await Promise.all(results)).reduce(flat, []);
+}
+/**
+ * @param {Compilation} compilation
+ * @returns {LintResultMap}
+ */
+
+
+function getResultStorage({
+  compiler
+}) {
+  let storage = resultStorage.get(compiler);
+
+  if (!storage) {
+    resultStorage.set(compiler, storage = {});
+  }
+
+  return storage;
+}
+/**
+ * @param {string | string[]} x
+ */
+
+
+function asList(x) {
+  /* istanbul ignore next */
+  return Array.isArray(x) ? x : [x];
+}
+
+module.exports = linter;
Index: frontend/node_modules/eslint-webpack-plugin/dist/options.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/options.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/options.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,103 @@
+"use strict";
+
+const {
+  validate
+} = require('schema-utils');
+
+const schema = require('./options.json');
+/** @typedef {import("eslint").ESLint.Options} ESLintOptions */
+
+/** @typedef {import('eslint').ESLint.LintResult} LintResult */
+
+/** @typedef {import('eslint').ESLint.LintResultData} LintResultData */
+
+/**
+ * @callback FormatterFunction
+ * @param {LintResult[]} results
+ * @param {LintResultData=} data
+ * @returns {string}
+ */
+
+/**
+ * @typedef {Object} OutputReport
+ * @property {string=} filePath
+ * @property {string|FormatterFunction=} formatter
+ */
+
+/**
+ * @typedef {Object} PluginOptions
+ * @property {string=} context
+ * @property {boolean=} emitError
+ * @property {boolean=} emitWarning
+ * @property {string=} eslintPath
+ * @property {string|string[]=} exclude
+ * @property {string|string[]=} extensions
+ * @property {boolean=} failOnError
+ * @property {boolean=} failOnWarning
+ * @property {string|string[]=} files
+ * @property {boolean=} fix
+ * @property {string|FormatterFunction=} formatter
+ * @property {boolean=} lintDirtyModulesOnly
+ * @property {boolean=} quiet
+ * @property {OutputReport=} outputReport
+ * @property {number|boolean=} threads
+ * @property {RegExp|RegExp[]=} resourceQueryExclude
+ */
+
+/** @typedef {PluginOptions & ESLintOptions} Options */
+
+/**
+ * @param {Options} pluginOptions
+ * @returns {PluginOptions}
+ */
+
+
+function getOptions(pluginOptions) {
+  const options = {
+    extensions: 'js',
+    emitError: true,
+    emitWarning: true,
+    failOnError: true,
+    resourceQueryExclude: [],
+    ...pluginOptions,
+    ...(pluginOptions.quiet ? {
+      emitError: true,
+      emitWarning: false
+    } : {})
+  }; // @ts-ignore
+
+  validate(schema, options, {
+    name: 'ESLint Webpack Plugin',
+    baseDataPath: 'options'
+  });
+  return options;
+}
+/**
+ * @param {Options} loaderOptions
+ * @returns {ESLintOptions}
+ */
+
+
+function getESLintOptions(loaderOptions) {
+  const eslintOptions = { ...loaderOptions
+  }; // Keep the fix option because it is common to both the loader and ESLint.
+
+  const {
+    fix,
+    extensions,
+    ...eslintOnlyOptions
+  } = schema.properties; // No need to guard the for-in because schema.properties has hardcoded keys.
+  // eslint-disable-next-line guard-for-in
+
+  for (const option in eslintOnlyOptions) {
+    // @ts-ignore
+    delete eslintOptions[option];
+  }
+
+  return eslintOptions;
+}
+
+module.exports = {
+  getOptions,
+  getESLintOptions
+};
Index: frontend/node_modules/eslint-webpack-plugin/dist/options.json
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/options.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/options.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+{
+  "type": "object",
+  "additionalProperties": true,
+  "properties": {
+    "context": {
+      "description": "A string indicating the root of your files.",
+      "type": "string"
+    },
+    "emitError": {
+      "description": "The errors found will always be emitted, to disable set to `false`.",
+      "type": "boolean"
+    },
+    "emitWarning": {
+      "description": "The warnings found will always be emitted, to disable set to `false`.",
+      "type": "boolean"
+    },
+    "eslintPath": {
+      "description": "Path to `eslint` instance that will be used for linting. If the `eslintPath` is a folder like a official eslint, or specify a `formatter` option. now you dont have to install `eslint`.",
+      "type": "string"
+    },
+    "exclude": {
+      "description": "Specify the files and/or directories to exclude. Must be relative to `options.context`.",
+      "anyOf": [{ "type": "string" }, { "type": "array" }]
+    },
+    "resourceQueryExclude": {
+      "description": "Specify the resource query to exclude.",
+      "anyOf": [{ "instanceof": "RegExp" }, { "type": "array" }]
+    },
+    "failOnError": {
+      "description": "Will cause the module build to fail if there are any errors, to disable set to `false`.",
+      "type": "boolean"
+    },
+    "failOnWarning": {
+      "description": "Will cause the module build to fail if there are any warnings, if set to `true`.",
+      "type": "boolean"
+    },
+    "files": {
+      "description": "Specify the files and/or directories to traverse. Must be relative to `options.context`.",
+      "anyOf": [{ "type": "string" }, { "type": "array" }]
+    },
+    "extensions": {
+      "description": "Specify extensions that should be checked.",
+      "anyOf": [{ "type": "string" }, { "type": "array" }]
+    },
+    "fix": {
+      "description": "Will enable ESLint autofix feature",
+      "type": "boolean"
+    },
+    "formatter": {
+      "description": "Accepts a function that will have one argument: an array of eslint messages (object). The function must return the output as a string.",
+      "anyOf": [{ "type": "string" }, { "instanceof": "Function" }]
+    },
+    "lintDirtyModulesOnly": {
+      "description": "Lint only changed files, skip lint on start.",
+      "type": "boolean"
+    },
+    "quiet": {
+      "description": "Will process and report errors only and ignore warnings, if set to `true`.",
+      "type": "boolean"
+    },
+    "outputReport": {
+      "description": "Write the output of the errors to a file, for example a checkstyle xml file for use for reporting on Jenkins CI",
+      "anyOf": [
+        {
+          "type": "boolean"
+        },
+        {
+          "type": "object",
+          "additionalProperties": false,
+          "properties": {
+            "filePath": {
+              "description": "The `filePath` is relative to the webpack config: output.path",
+              "anyOf": [{ "type": "string" }]
+            },
+            "formatter": {
+              "description": "You can pass in a different formatter for the output file, if none is passed in the default/configured formatter will be used",
+              "anyOf": [{ "type": "string" }, { "instanceof": "Function" }]
+            }
+          }
+        }
+      ]
+    },
+    "threads": {
+      "description": "Default is false. Set to true for an auto-selected pool size based on number of cpus. Set to a number greater than 1 to set an explicit pool size. Set to false, 1, or less to disable and only run in main process.",
+      "anyOf": [{ "type": "number" }, { "type": "boolean" }]
+    }
+  }
+}
Index: frontend/node_modules/eslint-webpack-plugin/dist/utils.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,124 @@
+"use strict";
+
+const {
+  resolve
+} = require('path');
+
+const {
+  statSync
+} = require('fs');
+
+const normalizePath = require('normalize-path');
+/**
+ * @template T
+ * @param {T} value
+ * @return {
+   T extends (null | undefined)
+     ? []
+     : T extends string
+       ? [string]
+       : T extends readonly unknown[]
+         ? T
+         : T extends Iterable<infer T>
+           ? T[]
+           : [T]
+ }
+ */
+
+/* istanbul ignore next */
+
+
+function arrify(value) {
+  // eslint-disable-next-line no-undefined
+  if (value === null || value === undefined) {
+    // @ts-ignore
+    return [];
+  }
+
+  if (Array.isArray(value)) {
+    // @ts-ignore
+    return value;
+  }
+
+  if (typeof value === 'string') {
+    // @ts-ignore
+    return [value];
+  } // @ts-ignore
+
+
+  if (typeof value[Symbol.iterator] === 'function') {
+    // @ts-ignore
+    return [...value];
+  } // @ts-ignore
+
+
+  return [value];
+}
+/**
+ * @param {string|string[]} files
+ * @param {string} context
+ * @returns {string[]}
+ */
+
+
+function parseFiles(files, context) {
+  return arrify(files).map((
+  /** @type {string} */
+  file) => normalizePath(resolve(context, file)));
+}
+/**
+ * @param {string|string[]} patterns
+ * @param {string|string[]} extensions
+ * @returns {string[]}
+ */
+
+
+function parseFoldersToGlobs(patterns, extensions = []) {
+  const extensionsList = arrify(extensions);
+  const [prefix, postfix] = extensionsList.length > 1 ? ['{', '}'] : ['', ''];
+  const extensionsGlob = extensionsList.map((
+  /** @type {string} */
+  extension) => extension.replace(/^\./u, '')).join(',');
+  return arrify(patterns).map((
+  /** @type {string} */
+  pattern) => {
+    try {
+      // The patterns are absolute because they are prepended with the context.
+      const stats = statSync(pattern);
+      /* istanbul ignore else */
+
+      if (stats.isDirectory()) {
+        return pattern.replace(/[/\\]*?$/u, `/**${extensionsGlob ? `/*.${prefix + extensionsGlob + postfix}` : ''}`);
+      }
+    } catch (_) {// Return the pattern as is on error.
+    }
+
+    return pattern;
+  });
+}
+/**
+ * @param {string} _ key, but unused
+ * @param {any} value
+ */
+
+
+const jsonStringifyReplacerSortKeys = (_, value) => {
+  /**
+   * @param {{ [x: string]: any; }} sorted
+   * @param {string | number} key
+   */
+  const insert = (sorted, key) => {
+    // eslint-disable-next-line no-param-reassign
+    sorted[key] = value[key];
+    return sorted;
+  };
+
+  return value instanceof Object && !(value instanceof Array) ? Object.keys(value).sort().reduce(insert, {}) : value;
+};
+
+module.exports = {
+  arrify,
+  parseFiles,
+  parseFoldersToGlobs,
+  jsonStringifyReplacerSortKeys
+};
Index: frontend/node_modules/eslint-webpack-plugin/dist/worker.js
===================================================================
--- frontend/node_modules/eslint-webpack-plugin/dist/worker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/eslint-webpack-plugin/dist/worker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+"use strict";
+
+/** @typedef {import('eslint').ESLint} ESLint */
+
+/** @typedef {import('eslint').ESLint.Options} ESLintOptions */
+Object.assign(module.exports, {
+  lintFiles,
+  setup
+});
+/** @type {{ new (arg0: import("eslint").ESLint.Options): import("eslint").ESLint; outputFixes: (arg0: import("eslint").ESLint.LintResult[]) => any; }} */
+
+let ESLint;
+/** @type {ESLint} */
+
+let eslint;
+/** @type {boolean} */
+
+let fix;
+/**
+ * @typedef {object} setupOptions
+ * @property {string=} eslintPath - import path of eslint
+ * @property {ESLintOptions=} eslintOptions - linter options
+ *
+ * @param {setupOptions} arg0 - setup worker
+ */
+
+function setup({
+  eslintPath,
+  eslintOptions = {}
+}) {
+  fix = !!(eslintOptions && eslintOptions.fix);
+  ({
+    ESLint
+  } = require(eslintPath || 'eslint'));
+  eslint = new ESLint(eslintOptions);
+}
+/**
+ * @param {string | string[]} files
+ */
+
+
+async function lintFiles(files) {
+  const result = await eslint.lintFiles(files); // if enabled, use eslint autofixing where possible
+
+  if (fix) {
+    await ESLint.outputFixes(result);
+  }
+
+  return result;
+}
