Index: frontend/node_modules/tapable/lib/AsyncParallelBailHook.js
===================================================================
--- frontend/node_modules/tapable/lib/AsyncParallelBailHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/AsyncParallelBailHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,87 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class AsyncParallelBailHookCodeFactory extends HookCodeFactory {
+	content({ onError, onResult, onDone }) {
+		let code = "";
+		code += `var _results = new Array(${this.options.taps.length});\n`;
+		code += "var _checkDone = function() {\n";
+		code += "for(var i = 0; i < _results.length; i++) {\n";
+		code += "var item = _results[i];\n";
+		code += "if(item === undefined) return false;\n";
+		code += "if(item.result !== undefined) {\n";
+		code += onResult("item.result");
+		code += "return true;\n";
+		code += "}\n";
+		code += "if(item.error) {\n";
+		code += onError("item.error");
+		code += "return true;\n";
+		code += "}\n";
+		code += "}\n";
+		code += "return false;\n";
+		code += "}\n";
+		code += this.callTapsParallel({
+			onError: (i, err, done, doneBreak) => {
+				let code = "";
+				code += `if(${i} < _results.length && ((_results.length = ${
+					i + 1
+				}), (_results[${i}] = { error: ${err} }), _checkDone())) {\n`;
+				code += doneBreak(true);
+				code += "} else {\n";
+				code += done();
+				code += "}\n";
+				return code;
+			},
+			onResult: (i, result, done, doneBreak) => {
+				let code = "";
+				code += `if(${i} < _results.length && (${result} !== undefined && (_results.length = ${
+					i + 1
+				}), (_results[${i}] = { result: ${result} }), _checkDone())) {\n`;
+				code += doneBreak(true);
+				code += "} else {\n";
+				code += done();
+				code += "}\n";
+				return code;
+			},
+			onTap: (i, run, done, _doneBreak) => {
+				let code = "";
+				if (i > 0) {
+					code += `if(${i} >= _results.length) {\n`;
+					code += done();
+					code += "} else {\n";
+				}
+				code += run();
+				if (i > 0) code += "}\n";
+				return code;
+			},
+			onDone
+		});
+		return code;
+	}
+}
+
+const factory = new AsyncParallelBailHookCodeFactory();
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function AsyncParallelBailHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = AsyncParallelBailHook;
+	hook.compile = COMPILE;
+	hook._call = undefined;
+	hook.call = undefined;
+	return hook;
+}
+
+AsyncParallelBailHook.prototype = null;
+
+module.exports = AsyncParallelBailHook;
Index: frontend/node_modules/tapable/lib/AsyncParallelHook.js
===================================================================
--- frontend/node_modules/tapable/lib/AsyncParallelHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/AsyncParallelHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class AsyncParallelHookCodeFactory extends HookCodeFactory {
+	content({ onError, onDone }) {
+		return this.callTapsParallel({
+			onError: (i, err, done, doneBreak) => onError(err) + doneBreak(true),
+			onDone
+		});
+	}
+}
+
+const factory = new AsyncParallelHookCodeFactory();
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function AsyncParallelHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = AsyncParallelHook;
+	hook.compile = COMPILE;
+	hook._call = undefined;
+	hook.call = undefined;
+	return hook;
+}
+
+AsyncParallelHook.prototype = null;
+
+module.exports = AsyncParallelHook;
Index: frontend/node_modules/tapable/lib/AsyncSeriesBailHook.js
===================================================================
--- frontend/node_modules/tapable/lib/AsyncSeriesBailHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/AsyncSeriesBailHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,42 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class AsyncSeriesBailHookCodeFactory extends HookCodeFactory {
+	content({ onError, onResult, resultReturns, onDone }) {
+		return this.callTapsSeries({
+			onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true),
+			onResult: (i, result, next) =>
+				`if(${result} !== undefined) {\n${onResult(
+					result
+				)}\n} else {\n${next()}}\n`,
+			resultReturns,
+			onDone
+		});
+	}
+}
+
+const factory = new AsyncSeriesBailHookCodeFactory();
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function AsyncSeriesBailHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = AsyncSeriesBailHook;
+	hook.compile = COMPILE;
+	hook._call = undefined;
+	hook.call = undefined;
+	return hook;
+}
+
+AsyncSeriesBailHook.prototype = null;
+
+module.exports = AsyncSeriesBailHook;
Index: frontend/node_modules/tapable/lib/AsyncSeriesHook.js
===================================================================
--- frontend/node_modules/tapable/lib/AsyncSeriesHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/AsyncSeriesHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class AsyncSeriesHookCodeFactory extends HookCodeFactory {
+	content({ onError, onDone }) {
+		return this.callTapsSeries({
+			onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true),
+			onDone
+		});
+	}
+}
+
+const factory = new AsyncSeriesHookCodeFactory();
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function AsyncSeriesHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = AsyncSeriesHook;
+	hook.compile = COMPILE;
+	hook._call = undefined;
+	hook.call = undefined;
+	return hook;
+}
+
+AsyncSeriesHook.prototype = null;
+
+module.exports = AsyncSeriesHook;
Index: frontend/node_modules/tapable/lib/AsyncSeriesLoopHook.js
===================================================================
--- frontend/node_modules/tapable/lib/AsyncSeriesLoopHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/AsyncSeriesLoopHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class AsyncSeriesLoopHookCodeFactory extends HookCodeFactory {
+	content({ onError, onDone }) {
+		return this.callTapsLooping({
+			onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true),
+			onDone
+		});
+	}
+}
+
+const factory = new AsyncSeriesLoopHookCodeFactory();
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function AsyncSeriesLoopHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = AsyncSeriesLoopHook;
+	hook.compile = COMPILE;
+	hook._call = undefined;
+	hook.call = undefined;
+	return hook;
+}
+
+AsyncSeriesLoopHook.prototype = null;
+
+module.exports = AsyncSeriesLoopHook;
Index: frontend/node_modules/tapable/lib/AsyncSeriesWaterfallHook.js
===================================================================
--- frontend/node_modules/tapable/lib/AsyncSeriesWaterfallHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/AsyncSeriesWaterfallHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class AsyncSeriesWaterfallHookCodeFactory extends HookCodeFactory {
+	content({ onError, onResult, _onDone }) {
+		return this.callTapsSeries({
+			onError: (i, err, next, doneBreak) => onError(err) + doneBreak(true),
+			onResult: (i, result, next) => {
+				let code = "";
+				code += `if(${result} !== undefined) {\n`;
+				code += `${this._args[0]} = ${result};\n`;
+				code += "}\n";
+				code += next();
+				return code;
+			},
+			onDone: () => onResult(this._args[0])
+		});
+	}
+}
+
+const factory = new AsyncSeriesWaterfallHookCodeFactory();
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function AsyncSeriesWaterfallHook(args = [], name = undefined) {
+	if (args.length < 1) {
+		throw new Error("Waterfall hooks must have at least one argument");
+	}
+	const hook = new Hook(args, name);
+	hook.constructor = AsyncSeriesWaterfallHook;
+	hook.compile = COMPILE;
+	hook._call = undefined;
+	hook.call = undefined;
+	return hook;
+}
+
+AsyncSeriesWaterfallHook.prototype = null;
+
+module.exports = AsyncSeriesWaterfallHook;
Index: frontend/node_modules/tapable/lib/Hook.js
===================================================================
--- frontend/node_modules/tapable/lib/Hook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/Hook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,233 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const util = require("util");
+
+const deprecateContext = util.deprecate(
+	() => {},
+	"Hook.context is deprecated and will be removed"
+);
+
+function CALL_DELEGATE(...args) {
+	this.call = this._createCall("sync");
+	return this.call(...args);
+}
+
+function CALL_ASYNC_DELEGATE(...args) {
+	this.callAsync = this._createCall("async");
+	return this.callAsync(...args);
+}
+
+function PROMISE_DELEGATE(...args) {
+	this.promise = this._createCall("promise");
+	return this.promise(...args);
+}
+
+class Hook {
+	constructor(args = [], name = undefined) {
+		this._args = args;
+		this.name = name;
+		this.taps = [];
+		this.interceptors = [];
+		this._call = CALL_DELEGATE;
+		this.call = CALL_DELEGATE;
+		this._callAsync = CALL_ASYNC_DELEGATE;
+		this.callAsync = CALL_ASYNC_DELEGATE;
+		this._promise = PROMISE_DELEGATE;
+		this.promise = PROMISE_DELEGATE;
+		this._x = undefined;
+
+		// eslint-disable-next-line no-self-assign
+		this.compile = this.compile;
+		// eslint-disable-next-line no-self-assign
+		this.tap = this.tap;
+		// eslint-disable-next-line no-self-assign
+		this.tapAsync = this.tapAsync;
+		// eslint-disable-next-line no-self-assign
+		this.tapPromise = this.tapPromise;
+	}
+
+	compile(_options) {
+		throw new Error("Abstract: should be overridden");
+	}
+
+	_createCall(type) {
+		return this.compile({
+			taps: this.taps,
+			interceptors: this.interceptors,
+			args: this._args,
+			type
+		});
+	}
+
+	_tap(type, options, fn) {
+		if (typeof options === "string") {
+			// Fast path: a string options ("name") is by far the most common
+			// case. Build the final descriptor in a single allocation instead
+			// of creating `{ name }` and then `Object.assign`ing it.
+			const name = options.trim();
+			if (name === "") {
+				throw new Error("Missing name for tap");
+			}
+			options = { type, fn, name };
+		} else {
+			if (typeof options !== "object" || options === null) {
+				throw new Error("Invalid tap options");
+			}
+			let { name } = options;
+			if (typeof name === "string") {
+				name = name.trim();
+			}
+			if (typeof name !== "string" || name === "") {
+				throw new Error("Missing name for tap");
+			}
+			if (typeof options.context !== "undefined") {
+				deprecateContext();
+			}
+			// Fast path: only `name` is set. Build the descriptor as a literal
+			// so `_insert` and downstream consumers see the same hidden class
+			// as the string-options path, avoiding a polymorphic call site.
+			// Scan with `for...in` (cheaper than allocating `Object.keys`)
+			// to verify no other user-provided properties exist - e.g.
+			// webpack's `additionalAssets` - otherwise they'd be dropped.
+			let onlyName = true;
+			for (const key in options) {
+				if (key !== "name") {
+					onlyName = false;
+					break;
+				}
+			}
+			if (onlyName) {
+				options = { type, fn, name };
+			} else {
+				options.name = name;
+				// Preserve previous precedence: user-provided keys win over the internal `type`/`fn`.
+				options = Object.assign({ type, fn }, options);
+			}
+		}
+		options = this._runRegisterInterceptors(options);
+		this._insert(options);
+	}
+
+	tap(options, fn) {
+		this._tap("sync", options, fn);
+	}
+
+	tapAsync(options, fn) {
+		this._tap("async", options, fn);
+	}
+
+	tapPromise(options, fn) {
+		this._tap("promise", options, fn);
+	}
+
+	_runRegisterInterceptors(options) {
+		const { interceptors } = this;
+		const { length } = interceptors;
+		// Common case: no interceptors.
+		if (length === 0) return options;
+		for (let i = 0; i < length; i++) {
+			const interceptor = interceptors[i];
+			if (interceptor.register) {
+				const newOptions = interceptor.register(options);
+				if (newOptions !== undefined) {
+					options = newOptions;
+				}
+			}
+		}
+		return options;
+	}
+
+	withOptions(options) {
+		const mergeOptions = (opt) =>
+			Object.assign({}, options, typeof opt === "string" ? { name: opt } : opt);
+
+		return {
+			name: this.name,
+			tap: (opt, fn) => this.tap(mergeOptions(opt), fn),
+			tapAsync: (opt, fn) => this.tapAsync(mergeOptions(opt), fn),
+			tapPromise: (opt, fn) => this.tapPromise(mergeOptions(opt), fn),
+			intercept: (interceptor) => this.intercept(interceptor),
+			isUsed: () => this.isUsed(),
+			withOptions: (opt) => this.withOptions(mergeOptions(opt))
+		};
+	}
+
+	isUsed() {
+		return this.taps.length > 0 || this.interceptors.length > 0;
+	}
+
+	intercept(interceptor) {
+		this._resetCompilation();
+		this.interceptors.push(Object.assign({}, interceptor));
+		if (interceptor.register) {
+			for (let i = 0; i < this.taps.length; i++) {
+				this.taps[i] = interceptor.register(this.taps[i]);
+			}
+		}
+	}
+
+	_resetCompilation() {
+		this.call = this._call;
+		this.callAsync = this._callAsync;
+		this.promise = this._promise;
+	}
+
+	_insert(item) {
+		this._resetCompilation();
+		const { taps } = this;
+		const stage = typeof item.stage === "number" ? item.stage : 0;
+
+		// Fast path: the overwhelmingly common `hook.tap("name", fn)` case
+		// has no `before` and default stage 0. If the list is empty or the
+		// last tap's stage is <= the new item's stage the item belongs at
+		// the end - append in O(1), skipping the Set allocation and the
+		// shift loop.
+		if (!(typeof item.before === "string" || Array.isArray(item.before))) {
+			const n = taps.length;
+			if (n === 0 || (taps[n - 1].stage || 0) <= stage) {
+				taps[n] = item;
+				return;
+			}
+		}
+
+		let before;
+
+		if (typeof item.before === "string") {
+			before = new Set([item.before]);
+		} else if (Array.isArray(item.before)) {
+			before = new Set(item.before);
+		}
+
+		let i = taps.length;
+
+		while (i > 0) {
+			i--;
+			const tap = taps[i];
+			taps[i + 1] = tap;
+			const xStage = tap.stage || 0;
+			if (before) {
+				if (before.has(tap.name)) {
+					before.delete(tap.name);
+					continue;
+				}
+				if (before.size > 0) {
+					continue;
+				}
+			}
+			if (xStage > stage) {
+				continue;
+			}
+			i++;
+			break;
+		}
+		taps[i] = item;
+	}
+}
+
+Object.setPrototypeOf(Hook.prototype, null);
+
+module.exports = Hook;
Index: frontend/node_modules/tapable/lib/HookCodeFactory.js
===================================================================
--- frontend/node_modules/tapable/lib/HookCodeFactory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/HookCodeFactory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,490 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+class HookCodeFactory {
+	constructor(config) {
+		this.config = config;
+		this.options = undefined;
+		this._args = undefined;
+	}
+
+	create(options) {
+		this.init(options);
+		let fn;
+		switch (options.type) {
+			case "sync":
+				fn = new Function(
+					this.args(),
+					`"use strict";\n${this.header()}${this.contentWithInterceptors({
+						onError: (err) => `throw ${err};\n`,
+						onResult: (result) => `return ${result};\n`,
+						resultReturns: true,
+						onDone: () => "",
+						rethrowIfPossible: true
+					})}`
+				);
+				break;
+			case "async":
+				fn = new Function(
+					this.args({
+						after: "_callback"
+					}),
+					`"use strict";\n${this.header()}${this.contentWithInterceptors({
+						onError: (err) => `_callback(${err});\n`,
+						onResult: (result) => `_callback(null, ${result});\n`,
+						onDone: () => "_callback();\n"
+					})}`
+				);
+				break;
+			case "promise": {
+				let errorHelperUsed = false;
+				const content = this.contentWithInterceptors({
+					onError: (err) => {
+						errorHelperUsed = true;
+						return `_error(${err});\n`;
+					},
+					onResult: (result) => `_resolve(${result});\n`,
+					onDone: () => "_resolve();\n"
+				});
+				let code = "";
+				code += '"use strict";\n';
+				code += this.header();
+				code += "return new Promise((function(_resolve, _reject) {\n";
+				if (errorHelperUsed) {
+					code += "var _sync = true;\n";
+					code += "function _error(_err) {\n";
+					code += "if(_sync)\n";
+					code +=
+						"_resolve(Promise.resolve().then((function() { throw _err; })));\n";
+					code += "else\n";
+					code += "_reject(_err);\n";
+					code += "};\n";
+				}
+				code += content;
+				if (errorHelperUsed) {
+					code += "_sync = false;\n";
+				}
+				code += "}));\n";
+				fn = new Function(this.args(), code);
+				break;
+			}
+		}
+		this.deinit();
+		return fn;
+	}
+
+	setup(instance, options) {
+		const { taps } = options;
+		const { length } = taps;
+		const fns = Array.from({ length });
+		for (let i = 0; i < length; i++) {
+			fns[i] = taps[i].fn;
+		}
+		instance._x = fns;
+	}
+
+	/**
+	 * @param {{ type: "sync" | "promise" | "async", taps: Array<Tap>, interceptors: Array<Interceptor> }} options
+	 */
+	init(options) {
+		this.options = options;
+		// `_args` is only read (length / join / [0]) - never mutated - so we
+		// can share the caller's array directly instead of paying for a copy
+		// on every compile.
+		this._args = options.args;
+		this._joinedArgs = undefined;
+	}
+
+	deinit() {
+		this.options = undefined;
+		this._args = undefined;
+		this._joinedArgs = undefined;
+	}
+
+	contentWithInterceptors(options) {
+		if (this.options.interceptors.length > 0) {
+			const { onError, onResult, onDone } = options;
+			let code = "";
+			for (let i = 0; i < this.options.interceptors.length; i++) {
+				const interceptor = this.options.interceptors[i];
+				if (interceptor.call) {
+					code += `${this.getInterceptor(i)}.call(${this.args({
+						before: interceptor.context ? "_context" : undefined
+					})});\n`;
+				}
+			}
+			code += this.content(
+				Object.assign(options, {
+					onError:
+						onError &&
+						((err) => {
+							let code = "";
+							for (let i = 0; i < this.options.interceptors.length; i++) {
+								const interceptor = this.options.interceptors[i];
+								if (interceptor.error) {
+									code += `${this.getInterceptor(i)}.error(${err});\n`;
+								}
+							}
+							code += onError(err);
+							return code;
+						}),
+					onResult:
+						onResult &&
+						((result) => {
+							let code = "";
+							for (let i = 0; i < this.options.interceptors.length; i++) {
+								const interceptor = this.options.interceptors[i];
+								if (interceptor.result) {
+									code += `${this.getInterceptor(i)}.result(${result});\n`;
+								}
+							}
+							code += onResult(result);
+							return code;
+						}),
+					onDone:
+						onDone &&
+						(() => {
+							let code = "";
+							for (let i = 0; i < this.options.interceptors.length; i++) {
+								const interceptor = this.options.interceptors[i];
+								if (interceptor.done) {
+									code += `${this.getInterceptor(i)}.done();\n`;
+								}
+							}
+							code += onDone();
+							return code;
+						})
+				})
+			);
+			return code;
+		}
+		return this.content(options);
+	}
+
+	header() {
+		let code = "";
+		code += this.needContext() ? "var _context = {};\n" : "var _context;\n";
+		code += "var _x = this._x;\n";
+		if (this.options.interceptors.length > 0) {
+			code += "var _taps = this.taps;\n";
+			code += "var _interceptors = this.interceptors;\n";
+		}
+		return code;
+	}
+
+	needContext() {
+		const { taps } = this.options;
+		for (let i = 0; i < taps.length; i++) {
+			if (taps[i].context) return true;
+		}
+		return false;
+	}
+
+	callTap(tapIndex, { onError, onResult, onDone, rethrowIfPossible }) {
+		let code = "";
+		let hasTapCached = false;
+		for (let i = 0; i < this.options.interceptors.length; i++) {
+			const interceptor = this.options.interceptors[i];
+			if (interceptor.tap) {
+				if (!hasTapCached) {
+					code += `var _tap${tapIndex} = ${this.getTap(tapIndex)};\n`;
+					hasTapCached = true;
+				}
+				code += `${this.getInterceptor(i)}.tap(${
+					interceptor.context ? "_context, " : ""
+				}_tap${tapIndex});\n`;
+			}
+		}
+		code += `var _fn${tapIndex} = ${this.getTapFn(tapIndex)};\n`;
+		const tap = this.options.taps[tapIndex];
+		switch (tap.type) {
+			case "sync":
+				if (!rethrowIfPossible) {
+					code += `var _hasError${tapIndex} = false;\n`;
+					code += "try {\n";
+				}
+				if (onResult) {
+					code += `var _result${tapIndex} = _fn${tapIndex}(${this.args({
+						before: tap.context ? "_context" : undefined
+					})});\n`;
+				} else {
+					code += `_fn${tapIndex}(${this.args({
+						before: tap.context ? "_context" : undefined
+					})});\n`;
+				}
+				if (!rethrowIfPossible) {
+					code += "} catch(_err) {\n";
+					code += `_hasError${tapIndex} = true;\n`;
+					code += onError("_err");
+					code += "}\n";
+					code += `if(!_hasError${tapIndex}) {\n`;
+				}
+				if (onResult) {
+					code += onResult(`_result${tapIndex}`);
+				}
+				if (onDone) {
+					code += onDone();
+				}
+				if (!rethrowIfPossible) {
+					code += "}\n";
+				}
+				break;
+			case "async": {
+				let cbCode = "";
+				cbCode += onResult
+					? `(function(_err${tapIndex}, _result${tapIndex}) {\n`
+					: `(function(_err${tapIndex}) {\n`;
+				cbCode += `if(_err${tapIndex}) {\n`;
+				cbCode += onError(`_err${tapIndex}`);
+				cbCode += "} else {\n";
+				if (onResult) {
+					cbCode += onResult(`_result${tapIndex}`);
+				}
+				if (onDone) {
+					cbCode += onDone();
+				}
+				cbCode += "}\n";
+				cbCode += "})";
+				code += `_fn${tapIndex}(${this.args({
+					before: tap.context ? "_context" : undefined,
+					after: cbCode
+				})});\n`;
+				break;
+			}
+			case "promise":
+				code += `var _hasResult${tapIndex} = false;\n`;
+				code += `var _promise${tapIndex} = _fn${tapIndex}(${this.args({
+					before: tap.context ? "_context" : undefined
+				})});\n`;
+				code += `if (!_promise${tapIndex} || !_promise${tapIndex}.then)\n`;
+				code += `  throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise${tapIndex} + ')');\n`;
+				code += `_promise${tapIndex}.then((function(_result${tapIndex}) {\n`;
+				code += `_hasResult${tapIndex} = true;\n`;
+				if (onResult) {
+					code += onResult(`_result${tapIndex}`);
+				}
+				if (onDone) {
+					code += onDone();
+				}
+				code += `}), function(_err${tapIndex}) {\n`;
+				code += `if(_hasResult${tapIndex}) throw _err${tapIndex};\n`;
+				code += onError(
+					`!_err${tapIndex} ? new Error('Tap function (tapPromise) rejects "' + _err${tapIndex} + '" value') : _err${tapIndex}`
+				);
+				code += "});\n";
+				break;
+		}
+		return code;
+	}
+
+	callTapsSeries({
+		onError,
+		onResult,
+		resultReturns,
+		onDone,
+		doneReturns,
+		rethrowIfPossible
+	}) {
+		const { taps } = this.options;
+		const tapsLength = taps.length;
+		if (tapsLength === 0) return onDone();
+		// Inlined findIndex to avoid the callback allocation.
+		let firstAsync = -1;
+		for (let i = 0; i < tapsLength; i++) {
+			if (taps[i].type !== "sync") {
+				firstAsync = i;
+				break;
+			}
+		}
+		const somethingReturns = resultReturns || doneReturns;
+		// doneBreak doesn't depend on the loop variable - hoist to allocate once.
+		const doneBreak = (skipDone) => {
+			if (skipDone) return "";
+			return onDone();
+		};
+		let code = "";
+		let current = onDone;
+		let unrollCounter = 0;
+		for (let j = tapsLength - 1; j >= 0; j--) {
+			const i = j;
+			const unroll =
+				current !== onDone && (taps[i].type !== "sync" || unrollCounter++ > 20);
+			if (unroll) {
+				unrollCounter = 0;
+				code += `function _next${i}() {\n`;
+				code += current();
+				code += "}\n";
+				current = () => `${somethingReturns ? "return " : ""}_next${i}();\n`;
+			}
+			const done = current;
+			const content = this.callTap(i, {
+				onError: (error) => onError(i, error, done, doneBreak),
+				onResult:
+					onResult && ((result) => onResult(i, result, done, doneBreak)),
+				onDone: !onResult && done,
+				rethrowIfPossible:
+					rethrowIfPossible && (firstAsync < 0 || i < firstAsync)
+			});
+			current = () => content;
+		}
+		code += current();
+		return code;
+	}
+
+	callTapsLooping({ onError, onDone, rethrowIfPossible }) {
+		if (this.options.taps.length === 0) return onDone();
+		const syncOnly = this.options.taps.every((t) => t.type === "sync");
+		let code = "";
+		if (!syncOnly) {
+			code += "var _looper = (function() {\n";
+			code += "var _loopAsync = false;\n";
+		}
+		code += "var _loop;\n";
+		code += "do {\n";
+		code += "_loop = false;\n";
+		for (let i = 0; i < this.options.interceptors.length; i++) {
+			const interceptor = this.options.interceptors[i];
+			if (interceptor.loop) {
+				code += `${this.getInterceptor(i)}.loop(${this.args({
+					before: interceptor.context ? "_context" : undefined
+				})});\n`;
+			}
+		}
+		code += this.callTapsSeries({
+			onError,
+			onResult: (i, result, next, doneBreak) => {
+				let code = "";
+				code += `if(${result} !== undefined) {\n`;
+				code += "_loop = true;\n";
+				if (!syncOnly) code += "if(_loopAsync) _looper();\n";
+				code += doneBreak(true);
+				code += "} else {\n";
+				code += next();
+				code += "}\n";
+				return code;
+			},
+			onDone:
+				onDone &&
+				(() => {
+					let code = "";
+					code += "if(!_loop) {\n";
+					code += onDone();
+					code += "}\n";
+					return code;
+				}),
+			rethrowIfPossible: rethrowIfPossible && syncOnly
+		});
+		code += "} while(_loop);\n";
+		if (!syncOnly) {
+			code += "_loopAsync = true;\n";
+			code += "});\n";
+			code += "_looper();\n";
+		}
+		return code;
+	}
+
+	callTapsParallel({
+		onError,
+		onResult,
+		onDone,
+		rethrowIfPossible,
+		onTap = (i, run) => run()
+	}) {
+		const { taps } = this.options;
+		const tapsLength = taps.length;
+		if (tapsLength <= 1) {
+			return this.callTapsSeries({
+				onError,
+				onResult,
+				onDone,
+				rethrowIfPossible
+			});
+		}
+		// done and doneBreak don't depend on the loop variable - hoist them
+		// so they're allocated once per compile instead of once per tap.
+		const done = () => {
+			if (onDone) return "if(--_counter === 0) _done();\n";
+			return "--_counter;";
+		};
+		const doneBreak = (skipDone) => {
+			if (skipDone || !onDone) return "_counter = 0;\n";
+			return "_counter = 0;\n_done();\n";
+		};
+		let code = "";
+		code += "do {\n";
+		code += `var _counter = ${tapsLength};\n`;
+		if (onDone) {
+			code += "var _done = (function() {\n";
+			code += onDone();
+			code += "});\n";
+		}
+		for (let i = 0; i < tapsLength; i++) {
+			code += "if(_counter <= 0) break;\n";
+			code += onTap(
+				i,
+				() =>
+					this.callTap(i, {
+						onError: (error) => {
+							let code = "";
+							code += "if(_counter > 0) {\n";
+							code += onError(i, error, done, doneBreak);
+							code += "}\n";
+							return code;
+						},
+						onResult:
+							onResult &&
+							((result) => {
+								let code = "";
+								code += "if(_counter > 0) {\n";
+								code += onResult(i, result, done, doneBreak);
+								code += "}\n";
+								return code;
+							}),
+						onDone: !onResult && (() => done()),
+						rethrowIfPossible
+					}),
+				done,
+				doneBreak
+			);
+		}
+		code += "} while(false);\n";
+		return code;
+	}
+
+	args({ before, after } = {}) {
+		// Hot during code generation. Join `_args` once and cache the result,
+		// then build the customized variants via string concat instead of
+		// allocating temporary `[before, ...allArgs]` / `[...allArgs, after]`
+		// arrays and re-joining.
+		let joined = this._joinedArgs;
+		if (joined === undefined) {
+			joined = this._args.length === 0 ? "" : this._args.join(", ");
+			this._joinedArgs = joined;
+		}
+		if (!before && !after) return joined;
+		if (joined.length === 0) {
+			if (before && after) return `${before}, ${after}`;
+			return before || after;
+		}
+		if (before && after) return `${before}, ${joined}, ${after}`;
+		if (before) return `${before}, ${joined}`;
+		return `${joined}, ${after}`;
+	}
+
+	getTapFn(idx) {
+		return `_x[${idx}]`;
+	}
+
+	getTap(idx) {
+		return `_taps[${idx}]`;
+	}
+
+	getInterceptor(idx) {
+		return `_interceptors[${idx}]`;
+	}
+}
+
+module.exports = HookCodeFactory;
Index: frontend/node_modules/tapable/lib/HookMap.js
===================================================================
--- frontend/node_modules/tapable/lib/HookMap.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/HookMap.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,73 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const util = require("util");
+
+const defaultFactory = (key, hook) => hook;
+
+class HookMap {
+	constructor(factory, name = undefined) {
+		this._map = new Map();
+		this.name = name;
+		this._factory = factory;
+		this._interceptors = [];
+	}
+
+	get(key) {
+		return this._map.get(key);
+	}
+
+	for(key) {
+		// Hot path: inline the map lookup to skip the `this.get(key)`
+		// indirection. This gets hit on every hook access in consumers
+		// like webpack.
+		const map = this._map;
+		const hook = map.get(key);
+		if (hook !== undefined) {
+			return hook;
+		}
+		let newHook = this._factory(key);
+		const interceptors = this._interceptors;
+		for (let i = 0; i < interceptors.length; i++) {
+			newHook = interceptors[i].factory(key, newHook);
+		}
+		map.set(key, newHook);
+		return newHook;
+	}
+
+	intercept(interceptor) {
+		this._interceptors.push(
+			Object.assign(
+				{
+					factory: defaultFactory
+				},
+				interceptor
+			)
+		);
+	}
+}
+
+HookMap.prototype.tap = util.deprecate(function tap(key, options, fn) {
+	return this.for(key).tap(options, fn);
+}, "HookMap#tap(key,…) is deprecated. Use HookMap#for(key).tap(…) instead.");
+
+HookMap.prototype.tapAsync = util.deprecate(function tapAsync(
+	key,
+	options,
+	fn
+) {
+	return this.for(key).tapAsync(options, fn);
+}, "HookMap#tapAsync(key,…) is deprecated. Use HookMap#for(key).tapAsync(…) instead.");
+
+HookMap.prototype.tapPromise = util.deprecate(function tapPromise(
+	key,
+	options,
+	fn
+) {
+	return this.for(key).tapPromise(options, fn);
+}, "HookMap#tapPromise(key,…) is deprecated. Use HookMap#for(key).tapPromise(…) instead.");
+
+module.exports = HookMap;
Index: frontend/node_modules/tapable/lib/MultiHook.js
===================================================================
--- frontend/node_modules/tapable/lib/MultiHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/MultiHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,57 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+class MultiHook {
+	constructor(hooks, name = undefined) {
+		this.hooks = hooks;
+		this.name = name;
+	}
+
+	tap(options, fn) {
+		const { hooks } = this;
+		for (let i = 0; i < hooks.length; i++) {
+			hooks[i].tap(options, fn);
+		}
+	}
+
+	tapAsync(options, fn) {
+		const { hooks } = this;
+		for (let i = 0; i < hooks.length; i++) {
+			hooks[i].tapAsync(options, fn);
+		}
+	}
+
+	tapPromise(options, fn) {
+		const { hooks } = this;
+		for (let i = 0; i < hooks.length; i++) {
+			hooks[i].tapPromise(options, fn);
+		}
+	}
+
+	isUsed() {
+		const { hooks } = this;
+		for (let i = 0; i < hooks.length; i++) {
+			if (hooks[i].isUsed()) return true;
+		}
+		return false;
+	}
+
+	intercept(interceptor) {
+		const { hooks } = this;
+		for (let i = 0; i < hooks.length; i++) {
+			hooks[i].intercept(interceptor);
+		}
+	}
+
+	withOptions(options) {
+		return new MultiHook(
+			this.hooks.map((hook) => hook.withOptions(options)),
+			this.name
+		);
+	}
+}
+
+module.exports = MultiHook;
Index: frontend/node_modules/tapable/lib/SyncBailHook.js
===================================================================
--- frontend/node_modules/tapable/lib/SyncBailHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/SyncBailHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,51 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class SyncBailHookCodeFactory extends HookCodeFactory {
+	content({ onError, onResult, resultReturns, onDone, rethrowIfPossible }) {
+		return this.callTapsSeries({
+			onError: (i, err) => onError(err),
+			onResult: (i, result, next) =>
+				`if(${result} !== undefined) {\n${onResult(
+					result
+				)};\n} else {\n${next()}}\n`,
+			resultReturns,
+			onDone,
+			rethrowIfPossible
+		});
+	}
+}
+
+const factory = new SyncBailHookCodeFactory();
+
+const TAP_ASYNC = () => {
+	throw new Error("tapAsync is not supported on a SyncBailHook");
+};
+
+const TAP_PROMISE = () => {
+	throw new Error("tapPromise is not supported on a SyncBailHook");
+};
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function SyncBailHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = SyncBailHook;
+	hook.tapAsync = TAP_ASYNC;
+	hook.tapPromise = TAP_PROMISE;
+	hook.compile = COMPILE;
+	return hook;
+}
+
+SyncBailHook.prototype = null;
+
+module.exports = SyncBailHook;
Index: frontend/node_modules/tapable/lib/SyncHook.js
===================================================================
--- frontend/node_modules/tapable/lib/SyncHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/SyncHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class SyncHookCodeFactory extends HookCodeFactory {
+	content({ onError, onDone, rethrowIfPossible }) {
+		return this.callTapsSeries({
+			onError: (i, err) => onError(err),
+			onDone,
+			rethrowIfPossible
+		});
+	}
+}
+
+const factory = new SyncHookCodeFactory();
+
+const TAP_ASYNC = () => {
+	throw new Error("tapAsync is not supported on a SyncHook");
+};
+
+const TAP_PROMISE = () => {
+	throw new Error("tapPromise is not supported on a SyncHook");
+};
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function SyncHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = SyncHook;
+	hook.tapAsync = TAP_ASYNC;
+	hook.tapPromise = TAP_PROMISE;
+	hook.compile = COMPILE;
+	return hook;
+}
+
+SyncHook.prototype = null;
+
+module.exports = SyncHook;
Index: frontend/node_modules/tapable/lib/SyncLoopHook.js
===================================================================
--- frontend/node_modules/tapable/lib/SyncLoopHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/SyncLoopHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class SyncLoopHookCodeFactory extends HookCodeFactory {
+	content({ onError, onDone, rethrowIfPossible }) {
+		return this.callTapsLooping({
+			onError: (i, err) => onError(err),
+			onDone,
+			rethrowIfPossible
+		});
+	}
+}
+
+const factory = new SyncLoopHookCodeFactory();
+
+const TAP_ASYNC = () => {
+	throw new Error("tapAsync is not supported on a SyncLoopHook");
+};
+
+const TAP_PROMISE = () => {
+	throw new Error("tapPromise is not supported on a SyncLoopHook");
+};
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function SyncLoopHook(args = [], name = undefined) {
+	const hook = new Hook(args, name);
+	hook.constructor = SyncLoopHook;
+	hook.tapAsync = TAP_ASYNC;
+	hook.tapPromise = TAP_PROMISE;
+	hook.compile = COMPILE;
+	return hook;
+}
+
+SyncLoopHook.prototype = null;
+
+module.exports = SyncLoopHook;
Index: frontend/node_modules/tapable/lib/SyncWaterfallHook.js
===================================================================
--- frontend/node_modules/tapable/lib/SyncWaterfallHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/SyncWaterfallHook.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,58 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+const Hook = require("./Hook");
+const HookCodeFactory = require("./HookCodeFactory");
+
+class SyncWaterfallHookCodeFactory extends HookCodeFactory {
+	content({ onError, onResult, resultReturns, rethrowIfPossible }) {
+		return this.callTapsSeries({
+			onError: (i, err) => onError(err),
+			onResult: (i, result, next) => {
+				let code = "";
+				code += `if(${result} !== undefined) {\n`;
+				code += `${this._args[0]} = ${result};\n`;
+				code += "}\n";
+				code += next();
+				return code;
+			},
+			onDone: () => onResult(this._args[0]),
+			doneReturns: resultReturns,
+			rethrowIfPossible
+		});
+	}
+}
+
+const factory = new SyncWaterfallHookCodeFactory();
+
+const TAP_ASYNC = () => {
+	throw new Error("tapAsync is not supported on a SyncWaterfallHook");
+};
+
+const TAP_PROMISE = () => {
+	throw new Error("tapPromise is not supported on a SyncWaterfallHook");
+};
+
+function COMPILE(options) {
+	factory.setup(this, options);
+	return factory.create(options);
+}
+
+function SyncWaterfallHook(args = [], name = undefined) {
+	if (args.length < 1) {
+		throw new Error("Waterfall hooks must have at least one argument");
+	}
+	const hook = new Hook(args, name);
+	hook.constructor = SyncWaterfallHook;
+	hook.tapAsync = TAP_ASYNC;
+	hook.tapPromise = TAP_PROMISE;
+	hook.compile = COMPILE;
+	return hook;
+}
+
+SyncWaterfallHook.prototype = null;
+
+module.exports = SyncWaterfallHook;
Index: frontend/node_modules/tapable/lib/index.js
===================================================================
--- frontend/node_modules/tapable/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,19 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+module.exports.AsyncParallelBailHook = require("./AsyncParallelBailHook");
+module.exports.AsyncParallelHook = require("./AsyncParallelHook");
+module.exports.AsyncSeriesBailHook = require("./AsyncSeriesBailHook");
+module.exports.AsyncSeriesHook = require("./AsyncSeriesHook");
+module.exports.AsyncSeriesLoopHook = require("./AsyncSeriesLoopHook");
+module.exports.AsyncSeriesWaterfallHook = require("./AsyncSeriesWaterfallHook");
+module.exports.HookMap = require("./HookMap");
+module.exports.MultiHook = require("./MultiHook");
+module.exports.SyncBailHook = require("./SyncBailHook");
+module.exports.SyncHook = require("./SyncHook");
+module.exports.SyncLoopHook = require("./SyncLoopHook");
+module.exports.SyncWaterfallHook = require("./SyncWaterfallHook");
+module.exports.__esModule = true;
Index: frontend/node_modules/tapable/lib/util-browser.js
===================================================================
--- frontend/node_modules/tapable/lib/util-browser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/tapable/lib/util-browser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+/*
+	MIT License http://www.opensource.org/licenses/mit-license.php
+	Author Tobias Koppers @sokra
+*/
+"use strict";
+
+module.exports.deprecate = (fn, msg) => {
+	let once = true;
+	return function deprecate() {
+		if (once) {
+			// eslint-disable-next-line no-console
+			console.warn(`DeprecationWarning: ${msg}`);
+			once = false;
+		}
+		// eslint-disable-next-line prefer-rest-params
+		return fn.apply(this, arguments);
+	};
+};
