Index: frontend/node_modules/for-each/.editorconfig
===================================================================
--- frontend/node_modules/for-each/.editorconfig	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/.editorconfig	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+root = true
+
+[*]
+indent_style = tab
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+max_line_length = 120
+
+[CHANGELOG.md]
+indent_style = space
+indent_size = 2
+
+[*.json]
+max_line_length = off
+
+[Makefile]
+max_line_length = off
Index: frontend/node_modules/for-each/.eslintrc
===================================================================
--- frontend/node_modules/for-each/.eslintrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/.eslintrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+{
+	"root": true,
+
+	"extends": "@ljharb",
+
+	"rules": {
+		"eqeqeq": [2, "allow-null"],
+		"func-name-matching": 0,
+		"func-style": 0,
+		"indent": [2, 4],
+		"max-nested-callbacks": [2, 3],
+		"max-params": [2, 3],
+		"max-statements": [2, 14],
+		"no-extra-parens": 0,
+		"no-invalid-this": 1,
+		"no-restricted-syntax": [2, "BreakStatement", "ContinueStatement", "DebuggerStatement", "LabeledStatement", "WithStatement"],
+	},
+
+	"overrides": [
+		{
+			"files": "test/**",
+			"rules": {
+				"array-bracket-newline": 0,
+				"array-element-newline": 0,
+				"max-statements-per-line": 0,
+				"no-magic-numbers": 0,
+			},
+		},
+	],
+}
Index: frontend/node_modules/for-each/.github/FUNDING.yml
===================================================================
--- frontend/node_modules/for-each/.github/FUNDING.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/.github/FUNDING.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: [ljharb]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: npm/for-each
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
Index: frontend/node_modules/for-each/.github/SECURITY.md
===================================================================
--- frontend/node_modules/for-each/.github/SECURITY.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/.github/SECURITY.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3 @@
+# Security
+
+Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
Index: frontend/node_modules/for-each/.nycrc
===================================================================
--- frontend/node_modules/for-each/.nycrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/.nycrc	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+{
+	"all": true,
+	"check-coverage": false,
+	"reporter": ["text-summary", "text", "html", "json"],
+	"exclude": [
+		"coverage"
+	]
+}
Index: frontend/node_modules/for-each/CHANGELOG.md
===================================================================
--- frontend/node_modules/for-each/CHANGELOG.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/CHANGELOG.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,107 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [v0.3.5](https://github.com/ljharb/for-each/compare/v0.3.4...v0.3.5) - 2025-02-10
+
+### Commits
+
+- [New] add types [`6483c1e`](https://github.com/ljharb/for-each/commit/6483c1e9b6177e5ca9ba506188300c5a25de26c2)
+
+## [v0.3.4](https://github.com/ljharb/for-each/compare/v0.3.3...v0.3.4) - 2025-01-24
+
+### Commits
+
+- [meta] use `auto-changelog` [`c16ee6a`](https://github.com/ljharb/for-each/commit/c16ee6a125eb3c6d30f626b4b02ec849a63fca28)
+- [Tests] add github actions [`379b59c`](https://github.com/ljharb/for-each/commit/379b59c8f282c2281ba668e3e028ad6410afb99b)
+- [meta] delete `.travis.yml` [`09e5c77`](https://github.com/ljharb/for-each/commit/09e5c779651215c41bd4727e266a5e7ebb3b0a4d)
+- [Dev Deps] update eslint things [`9163b86`](https://github.com/ljharb/for-each/commit/9163b86435be325965f096ac17793a0e783b1c1e)
+- [meta] consolidate eslintrc files [`f2ab52b`](https://github.com/ljharb/for-each/commit/f2ab52b6944fe8c1a189957889276950393eddb3)
+- [meta] add `funding` field and `FUNDING.yml` [`05d21b3`](https://github.com/ljharb/for-each/commit/05d21b382ccd4627b283d1a31c49935c7d79fd57)
+- [Tests] up to `node` `v10`; use `nvm install-latest-npm` [`7c06cbd`](https://github.com/ljharb/for-each/commit/7c06cbdabea81ba029cd466545dea5cb9f24f528)
+- [Tests] add `nyc` [`0f4643e`](https://github.com/ljharb/for-each/commit/0f4643e6a572bdc6967a17be8e7b959600edbbd2)
+- [meta] use `npmignore` [`39a975c`](https://github.com/ljharb/for-each/commit/39a975c8c6050586b93b5e0a98b20be44d1b38d4)
+- [meta] remove unnecessary `licenses` key [`3d064f1`](https://github.com/ljharb/for-each/commit/3d064f12167c12d8e1d1ee1447ee58d8211c63e1)
+- [Tests] use `npm audit` instead of long-dead `nsp` [`d4c722a`](https://github.com/ljharb/for-each/commit/d4c722a0f61f61d93965328f436f87421bce9973)
+- [Dev Deps] update `tape` [`552c1ae`](https://github.com/ljharb/for-each/commit/552c1ae6a01728ff312d47605dbdb961ef0ccbcc)
+- Update README.md [`d19acc2`](https://github.com/ljharb/for-each/commit/d19acc23624eed9d8f59b9fa64e6e3cba638aa52)
+- [meta] add missing `engines.node` [`8889b49`](https://github.com/ljharb/for-each/commit/8889b49bd737d7a72c2a515eb2ee39a01c813bac)
+- [meta] create SECURITY.md [`9069d42`](https://github.com/ljharb/for-each/commit/9069d42d245b02ae7c5f0c193fceb55427436e4e)
+- [Deps] update `is-callable` [`bfa51d1`](https://github.com/ljharb/for-each/commit/bfa51d18018477843147bcdcc6cc63eb045151f5)
+
+## [v0.3.3](https://github.com/ljharb/for-each/compare/v0.3.2...v0.3.3) - 2018-06-01
+
+### Commits
+
+- Add `npm run lint`, `npm run jscs`, and `npm run eslint` [`4a17d99`](https://github.com/ljharb/for-each/commit/4a17d99d7397dd2356530d238e0e6c37ef34a1d5)
+- Style cleanup: [`1df6824`](https://github.com/ljharb/for-each/commit/1df6824d96bfc293c0c9e6b78143b602c8d94986)
+- Update `eslint`, `tape`; use my personal shared `eslint` config. [`b8e7d85`](https://github.com/ljharb/for-each/commit/b8e7d850ec9010a7171d34297f7af74b90f28aac)
+- [Tests] remove jscs [`37e3557`](https://github.com/ljharb/for-each/commit/37e355784b4261dcf5004158a72c4b8a6c6c524f)
+- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `nsp`, `tape`; fix scripts [`566045d`](https://github.com/ljharb/for-each/commit/566045d84f2ee5dff7cc14805c4fdb1d13d2624d)
+- [Tests] up to `node` `v8`; newer npm breaks on older node [`07177dc`](https://github.com/ljharb/for-each/commit/07177dc9c8419b2a887c727ec576189a7c8e7837)
+- Run `npm run lint` as part of tests. [`a34ea05`](https://github.com/ljharb/for-each/commit/a34ea05f729e0987007670d5693e093c56865ef6)
+- Update `travis.yml` to test on the latest `node` and `io.js` [`354c843`](https://github.com/ljharb/for-each/commit/354c8434a166c7095c613e818c8d542fd1e2d630)
+- Update `eslint` [`3601c93`](https://github.com/ljharb/for-each/commit/3601c9348e2cfb29ed3cfee352c2c95d4a8de87f)
+- Update `tape`, `jscs`, `eslint`, `@ljharb/eslint-config` [`1aaff65`](https://github.com/ljharb/for-each/commit/1aaff65a55d8a054561251c6a2501c4dc42e1f99)
+- Only use `Function#call` to call the callback if the receiver is supplied, for performance. [`54b4775`](https://github.com/ljharb/for-each/commit/54b477571b4d7c11edccafd94f2e16380892ee5d)
+- [Dev Deps] update `jscs`, `eslint`, `@ljharb/eslint-config`, `nsp` [`6ba1cb8`](https://github.com/ljharb/for-each/commit/6ba1cb8a708e84ba4bb4067d31549829ec579d92)
+- [Dev Deps] update `tape`, `eslint`, `jscs` [`8f5e1d5`](https://github.com/ljharb/for-each/commit/8f5e1d5fcabaf3abaa6ce2d3e6dd095f0dedfc4e)
+- Add "license" to `package.json`, matching the LICENSE file. [`defc2c3`](https://github.com/ljharb/for-each/commit/defc2c35ffa7c9d4fbcf846f28b436f0083a381c)
+- Update `eslint` [`05d1850`](https://github.com/ljharb/for-each/commit/05d18503dd0ec709f93df5c905bd2d0ce51323c3)
+- [Tests] on `io.js` `v3.3`, `node` `v4.0` [`e8395a4`](https://github.com/ljharb/for-each/commit/e8395a43feef399299839c8d466ddd9dca0c3268)
+- Add `npm run security` [`0a45177`](https://github.com/ljharb/for-each/commit/0a45177290b1de71094ddd322ef4a504458e901d)
+- Only apps should have lockfiles. [`6268d7b`](https://github.com/ljharb/for-each/commit/6268d7b39edd06ef5a283c7afdb6c823077db777)
+- [Dev Deps] update `nsp`, `tape`, `eslint` [`b95939f`](https://github.com/ljharb/for-each/commit/b95939f66a3dad590b3bc42c53535e77c1bfc114)
+- Use `is-callable` instead of `is-function`, to cover ES6 environments with `Symbol.toStringTag` [`4095d33`](https://github.com/ljharb/for-each/commit/4095d334581c1caee92f595c299ffc479806dc3f)
+- Test on `io.js` `v2.2` [`7b44f98`](https://github.com/ljharb/for-each/commit/7b44f98c217291a92385ddd3903d4974e049d762)
+- Some old browsers choke on variables named "toString". [`4f1b626`](https://github.com/ljharb/for-each/commit/4f1b626eb91fcdc0e9018472a702aea713799190)
+- Update `is-function`, `tape` [`3ceaf32`](https://github.com/ljharb/for-each/commit/3ceaf3240ef7d1b261cf510eb932cf540291187b)
+- Test up to `io.js` `v3.0` [`3c1377a`](https://github.com/ljharb/for-each/commit/3c1377a31adf003323f4846a97e8f7c8fd51b5d2)
+- [Deps] update `is-callable` [`f5c62d0`](https://github.com/ljharb/for-each/commit/f5c62d034b582a15bcb1f1cadace4e9c84f1780a)
+- Test on `io.js` `v2.4` [`db86c85`](https://github.com/ljharb/for-each/commit/db86c85641d053a1dc4e570e8c8afbea915f78c0)
+- Test on `io.js` `v2.3` [`2f04ca8`](https://github.com/ljharb/for-each/commit/2f04ca885adb4a8ccca658739f771a7f78522d03)
+
+## [v0.3.2](https://github.com/ljharb/for-each/compare/v0.3.1...v0.3.2) - 2014-01-07
+
+### Merged
+
+- works down to IE6 [`#5`](https://github.com/ljharb/for-each/pull/5)
+
+## [v0.3.1](https://github.com/ljharb/for-each/compare/v0.3.0...v0.3.1) - 2014-01-06
+
+## [v0.3.0](https://github.com/ljharb/for-each/compare/v0.2.0...v0.3.0) - 2014-01-06
+
+### Merged
+
+- remove use of Object.keys [`#4`](https://github.com/ljharb/for-each/pull/4)
+- Update tape. [`#3`](https://github.com/ljharb/for-each/pull/3)
+- regex is not a function [`#2`](https://github.com/ljharb/for-each/pull/2)
+- Add testling [`#1`](https://github.com/ljharb/for-each/pull/1)
+
+### Commits
+
+- Add testling. [`a24b521`](https://github.com/ljharb/for-each/commit/a24b52111937d509a3b5f58106c8835283de7146)
+- Add array example to README [`9bd70c2`](https://github.com/ljharb/for-each/commit/9bd70c2ceafddfc734a80e0fea2bbac00afa963a)
+- Regexes are considered functions in older browsers. [`403f649`](https://github.com/ljharb/for-each/commit/403f6490f903984adea1771af29c41fd2b1e4b64)
+- Adding android browser to testling. [`a4c5825`](https://github.com/ljharb/for-each/commit/a4c5825bf8abd13589b9a9662c9d3deaf89cbf66)
+
+## [v0.2.0](https://github.com/ljharb/for-each/compare/v0.1.0...v0.2.0) - 2013-05-10
+
+### Commits
+
+- Adding tests. [`7e74213`](https://github.com/ljharb/for-each/commit/7e74213d1b5d01b19249c3e3037302bd7fc74f1c)
+- Adding proper array indexing, as well as string support. [`d36f794`](https://github.com/ljharb/for-each/commit/d36f794d6c0c5696bf1e4f8e79ae667858dfc11b)
+- Use tape instead of tap. [`016a3cf`](https://github.com/ljharb/for-each/commit/016a3cf706c78037384d4c378b2ebe6e702cbb02)
+- Requiring that the iterator is a function. [`cfedced`](https://github.com/ljharb/for-each/commit/cfedceda15ea2f7eb4acf079fb90ce17ec7da664)
+- Adding myself as a contributor :-) [`ff28fca`](https://github.com/ljharb/for-each/commit/ff28fca8ec30f6fdbb7af87c74ed35688e60d07a)
+- Adding node 0.10 to travis [`75f2460`](https://github.com/ljharb/for-each/commit/75f2460343d3ea58f91dad45f2eda478e3a4e412)
+
+## v0.1.0 - 2012-09-28
+
+### Commits
+
+- first [`2d3a6ed`](https://github.com/ljharb/for-each/commit/2d3a6ed63036455847937cf00bec56b59ab36a9d)
+- docs & travis [`ea4caad`](https://github.com/ljharb/for-each/commit/ea4caad8a8768992dcce29998e226484beed841c)
Index: frontend/node_modules/for-each/LICENSE
===================================================================
--- frontend/node_modules/for-each/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2012 Raynos.
+
+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/for-each/README.md
===================================================================
--- frontend/node_modules/for-each/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,39 @@
+# for-each [![build status][1]][2]
+
+[![browser support][3]][4]
+
+A better forEach.
+
+## Example
+
+Like `Array.prototype.forEach` but works on objects.
+
+```js
+var forEach = require("for-each")
+
+forEach({ key: "value" }, function (value, key, object) {
+    /* code */
+})
+```
+
+As a bonus, it's also a perfectly function shim/polyfill for arrays too!
+
+```js
+var forEach = require("for-each")
+
+forEach([1, 2, 3], function (value, index, array) {
+    /* code */
+})
+```
+
+## Installation
+
+`npm install for-each`
+
+## MIT Licenced
+
+  [1]: https://secure.travis-ci.org/Raynos/for-each.png
+  [2]: http://travis-ci.org/Raynos/for-each
+  [3]: https://ci.testling.com/Raynos/for-each.png
+  [4]: https://ci.testling.com/Raynos/for-each
+
Index: frontend/node_modules/for-each/index.d.ts
===================================================================
--- frontend/node_modules/for-each/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/index.d.ts	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+declare function forEach<O extends readonly unknown[], This = undefined>(
+    arr: O,
+    callback: (this: This | void, value: O[number], index: number, array: O) => void,
+    thisArg?: This,
+): void;
+
+declare function forEach<O extends ArrayLike<unknown>, This = undefined>(
+    arr: O,
+    callback: (this: This | void, value: O[number], index: number, array: O) => void,
+    thisArg?: This,
+): void;
+
+declare function forEach<O extends object, This = undefined>(
+    obj: O,
+    callback: (this: This | void, value: O[keyof O], key: keyof O, obj: O) => void,
+    thisArg?: This,
+): void;
+
+declare function forEach<O extends string, This = undefined>(
+    str: O,
+    callback: (this: This | void, value: O[number], index: number, str: O) => void,
+    thisArg: This,
+): void;
+
+export = forEach;
+
+declare function forEachInternal<O, C extends (this: This | void, value: unknown, index: PropertyKey, obj: O) => void, This = undefined>(
+	value: O,
+	callback: C,
+	thisArg?: This,
+): void;
+
+declare namespace forEach {
+	export type _internal = typeof forEachInternal;
+}
Index: frontend/node_modules/for-each/index.js
===================================================================
--- frontend/node_modules/for-each/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,69 @@
+'use strict';
+
+var isCallable = require('is-callable');
+
+var toStr = Object.prototype.toString;
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/** @type {<This, A extends readonly unknown[]>(arr: A, iterator: (this: This | void, value: A[number], index: number, arr: A) => void, receiver: This | undefined) => void} */
+var forEachArray = function forEachArray(array, iterator, receiver) {
+    for (var i = 0, len = array.length; i < len; i++) {
+        if (hasOwnProperty.call(array, i)) {
+            if (receiver == null) {
+                iterator(array[i], i, array);
+            } else {
+                iterator.call(receiver, array[i], i, array);
+            }
+        }
+    }
+};
+
+/** @type {<This, S extends string>(string: S, iterator: (this: This | void, value: S[number], index: number, string: S) => void, receiver: This | undefined) => void} */
+var forEachString = function forEachString(string, iterator, receiver) {
+    for (var i = 0, len = string.length; i < len; i++) {
+        // no such thing as a sparse string.
+        if (receiver == null) {
+            iterator(string.charAt(i), i, string);
+        } else {
+            iterator.call(receiver, string.charAt(i), i, string);
+        }
+    }
+};
+
+/** @type {<This, O>(obj: O, iterator: (this: This | void, value: O[keyof O], index: keyof O, obj: O) => void, receiver: This | undefined) => void} */
+var forEachObject = function forEachObject(object, iterator, receiver) {
+    for (var k in object) {
+        if (hasOwnProperty.call(object, k)) {
+            if (receiver == null) {
+                iterator(object[k], k, object);
+            } else {
+                iterator.call(receiver, object[k], k, object);
+            }
+        }
+    }
+};
+
+/** @type {(x: unknown) => x is readonly unknown[]} */
+function isArray(x) {
+    return toStr.call(x) === '[object Array]';
+}
+
+/** @type {import('.')._internal} */
+module.exports = function forEach(list, iterator, thisArg) {
+    if (!isCallable(iterator)) {
+        throw new TypeError('iterator must be a function');
+    }
+
+    var receiver;
+    if (arguments.length >= 3) {
+        receiver = thisArg;
+    }
+
+    if (isArray(list)) {
+        forEachArray(list, iterator, receiver);
+    } else if (typeof list === 'string') {
+        forEachString(list, iterator, receiver);
+    } else {
+        forEachObject(list, iterator, receiver);
+    }
+};
Index: frontend/node_modules/for-each/package.json
===================================================================
--- frontend/node_modules/for-each/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,76 @@
+{
+  "name": "for-each",
+  "version": "0.3.5",
+  "description": "A better forEach",
+  "keywords": [],
+  "author": "Raynos <raynos2@gmail.com>",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/Raynos/for-each.git"
+  },
+  "funding": {
+    "url": "https://github.com/sponsors/ljharb"
+  },
+  "main": "index",
+  "homepage": "https://github.com/Raynos/for-each",
+  "contributors": [
+    {
+      "name": "Jake Verbaten"
+    },
+    {
+      "name": "Jordan Harband",
+      "url": "https://github.com/ljharb"
+    }
+  ],
+  "bugs": {
+    "url": "https://github.com/Raynos/for-each/issues",
+    "email": "raynos2@gmail.com"
+  },
+  "license": "MIT",
+  "scripts": {
+    "prepack": "npmignore --auto --commentLines=autogenerated",
+    "pretest": "npm run lint",
+    "test": "npm run tests-only",
+    "tests-only": "nyc tape 'test/*.js'",
+    "posttest": "npx npm@\">= 10.2\" audit --production",
+    "lint": "eslint --ext=js,mjs .",
+    "postlint": "tsc && attw -P",
+    "version": "auto-changelog && git add CHANGELOG.md",
+    "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
+  },
+  "dependencies": {
+    "is-callable": "^1.2.7"
+  },
+  "devDependencies": {
+    "@arethetypeswrong/cli": "^0.17.3",
+    "@ljharb/eslint-config": "^21.1.1",
+    "@ljharb/tsconfig": "^0.2.3",
+    "@types/is-callable": "^1.1.2",
+    "@types/tape": "^5.8.1",
+    "auto-changelog": "^2.5.0",
+    "eslint": "=8.8.0",
+    "npmignore": "^0.3.1",
+    "nyc": "^10.3.2",
+    "tape": "^5.9.0",
+    "typescript": "next"
+  },
+  "testling": {
+    "files": "test/test.js"
+  },
+  "engines": {
+    "node": ">= 0.4"
+  },
+  "auto-changelog": {
+    "output": "CHANGELOG.md",
+    "template": "keepachangelog",
+    "unreleased": false,
+    "commitLimit": false,
+    "backfillLimit": false,
+    "hideCredit": true
+  },
+  "publishConfig": {
+    "ignore": [
+      ".github/workflows"
+    ]
+  }
+}
Index: frontend/node_modules/for-each/test/test.js
===================================================================
--- frontend/node_modules/for-each/test/test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/test/test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,224 @@
+'use strict';
+
+var test = require('tape');
+var forEach = require('../');
+
+test('forEach calls each iterator', function (t) {
+    var count = 0;
+    t.plan(4);
+
+    forEach({ a: 1, b: 2 }, function (value, key) {
+        if (count === 0) {
+            t.equal(value, 1);
+            t.equal(key, 'a');
+        } else {
+            t.equal(value, 2);
+            t.equal(key, 'b');
+        }
+        count += 1;
+    });
+});
+
+test('forEach calls iterator with correct this value', function (t) {
+    var thisValue = {};
+
+    t.plan(1);
+
+    forEach([0], function () {
+        t.equal(this, thisValue);
+    }, thisValue);
+});
+
+test('second argument: iterator', function (t) {
+    /** @type {unknown[]} */
+    var arr = [];
+
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr); }, TypeError, 'undefined is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, null); }, TypeError, 'null is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, ''); }, TypeError, 'string is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, /a/); }, TypeError, 'regex is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, true); }, TypeError, 'true is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, false); }, TypeError, 'false is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, NaN); }, TypeError, 'NaN is not a function');
+    // @ts-expect-error
+    t['throws'](function () { forEach(arr, 42); }, TypeError, '42 is not a function');
+
+    t.doesNotThrow(function () { forEach(arr, function () {}); }, 'function is a function');
+    // @ts-expect-error TODO fixme
+    t.doesNotThrow(function () { forEach(arr, setTimeout); }, 'setTimeout is a function');
+
+    /* eslint-env browser */
+    if (typeof window !== 'undefined') {
+        t.doesNotThrow(function () { forEach(arr, window.alert); }, 'alert is a function');
+    }
+
+    t.end();
+});
+
+test('array', function (t) {
+    var arr = /** @type {const} */ ([1, 2, 3]);
+
+    t.test('iterates over every item', function (st) {
+        var index = 0;
+        forEach(arr, function () { index += 1; });
+        st.equal(index, arr.length, 'iterates ' + arr.length + ' times');
+        st.end();
+    });
+
+    t.test('first iterator argument', function (st) {
+        var index = 0;
+        st.plan(arr.length);
+
+        forEach(arr, function (item) {
+            st.equal(arr[index], item, 'item ' + index + ' is passed as first argument');
+            index += 1;
+        });
+
+        st.end();
+    });
+
+    t.test('second iterator argument', function (st) {
+        var counter = 0;
+        st.plan(arr.length);
+
+        forEach(arr, function (_item, index) {
+            st.equal(counter, index, 'index ' + index + ' is passed as second argument');
+            counter += 1;
+        });
+
+        st.end();
+    });
+
+    t.test('third iterator argument', function (st) {
+        st.plan(arr.length);
+
+        forEach(arr, function (_item, _index, array) {
+            st.deepEqual(arr, array, 'array is passed as third argument');
+        });
+
+        st.end();
+    });
+
+    t.test('context argument', function (st) {
+        var context = {};
+
+        forEach([], function () {
+            st.equal(this, context, '"this" is the passed context');
+        }, context);
+
+        st.end();
+    });
+
+    t.end();
+});
+
+test('object', function (t) {
+    var obj = {
+        a: 1,
+        b: 2,
+        c: 3
+    };
+    var keys = /** @type {const} */ (['a', 'b', 'c']);
+
+    /** @constructor */
+    function F() {
+        this.a = 1;
+        this.b = 2;
+    }
+    F.prototype.c = 3;
+    var fKeys = /** @type {const} */ (['a', 'b']);
+
+    t.test('iterates over every object literal key', function (st) {
+        var counter = 0;
+
+        forEach(obj, function () { counter += 1; });
+
+        st.equal(counter, keys.length, 'iterated ' + counter + ' times');
+
+        st.end();
+    });
+
+    t.test('iterates only over own keys', function (st) {
+        var counter = 0;
+
+        forEach(new F(), function () { counter += 1; });
+
+        st.equal(counter, fKeys.length, 'iterated ' + fKeys.length + ' times');
+
+        st.end();
+    });
+
+    t.test('first iterator argument', function (st) {
+        var index = 0;
+        st.plan(keys.length);
+
+        forEach(obj, function (item) {
+            st.equal(obj[keys[index]], item, 'item at key ' + keys[index] + ' is passed as first argument');
+            index += 1;
+        });
+
+        st.end();
+    });
+
+    t.test('second iterator argument', function (st) {
+        var counter = 0;
+        st.plan(keys.length);
+
+        forEach(obj, function (_item, key) {
+            st.equal(keys[counter], key, 'key ' + key + ' is passed as second argument');
+            counter += 1;
+        });
+
+        st.end();
+    });
+
+    t.test('third iterator argument', function (st) {
+        st.plan(keys.length);
+
+        forEach(obj, function (_item, _key, object) {
+            st.deepEqual(obj, object, 'object is passed as third argument');
+        });
+
+        st.end();
+    });
+
+    t.test('context argument', function (st) {
+        var context = {};
+
+        forEach({}, function () {
+            st.equal(this, context, '"this" is the passed context');
+        }, context);
+
+        st.end();
+    });
+
+    t.end();
+});
+
+test('string', function (t) {
+    var str = /** @type {const} */ ('str');
+
+    t.test('second iterator argument', function (st) {
+        var counter = 0;
+        st.plan((str.length * 2) + 1);
+
+        forEach(str, function (item, index) {
+            st.equal(counter, index, 'index ' + index + ' is passed as second argument');
+            st.equal(str.charAt(index), item);
+            counter += 1;
+        });
+
+        st.equal(counter, str.length, 'iterates ' + str.length + ' times');
+
+        st.end();
+    });
+
+    t.end();
+});
Index: frontend/node_modules/for-each/tsconfig.json
===================================================================
--- frontend/node_modules/for-each/tsconfig.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/for-each/tsconfig.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+{
+	"extends": "@ljharb/tsconfig",
+	"compilerOptions": {
+	},
+	"exclude": [
+		"coverage",
+	],
+}
