Index: frontend/node_modules/jsdom/lib/api.js
===================================================================
--- frontend/node_modules/jsdom/lib/api.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/api.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,333 @@
+"use strict";
+const path = require("path");
+const fs = require("fs").promises;
+const vm = require("vm");
+const toughCookie = require("tough-cookie");
+const sniffHTMLEncoding = require("html-encoding-sniffer");
+const whatwgURL = require("whatwg-url");
+const whatwgEncoding = require("whatwg-encoding");
+const { URL } = require("whatwg-url");
+const MIMEType = require("whatwg-mimetype");
+const idlUtils = require("./jsdom/living/generated/utils.js");
+const VirtualConsole = require("./jsdom/virtual-console.js");
+const { createWindow } = require("./jsdom/browser/Window.js");
+const { parseIntoDocument } = require("./jsdom/browser/parser");
+const { fragmentSerialization } = require("./jsdom/living/domparsing/serialization.js");
+const ResourceLoader = require("./jsdom/browser/resources/resource-loader.js");
+const NoOpResourceLoader = require("./jsdom/browser/resources/no-op-resource-loader.js");
+
+class CookieJar extends toughCookie.CookieJar {
+  constructor(store, options) {
+    // jsdom cookie jars must be loose by default
+    super(store, { looseMode: true, ...options });
+  }
+}
+
+const window = Symbol("window");
+let sharedFragmentDocument = null;
+
+class JSDOM {
+  constructor(input = "", options = {}) {
+    const mimeType = new MIMEType(options.contentType === undefined ? "text/html" : options.contentType);
+    const { html, encoding } = normalizeHTML(input, mimeType);
+
+    options = transformOptions(options, encoding, mimeType);
+
+    this[window] = createWindow(options.windowOptions);
+
+    const documentImpl = idlUtils.implForWrapper(this[window]._document);
+
+    options.beforeParse(this[window]._globalProxy);
+
+    parseIntoDocument(html, documentImpl);
+
+    documentImpl.close();
+  }
+
+  get window() {
+    // It's important to grab the global proxy, instead of just the result of `createWindow(...)`, since otherwise
+    // things like `window.eval` don't exist.
+    return this[window]._globalProxy;
+  }
+
+  get virtualConsole() {
+    return this[window]._virtualConsole;
+  }
+
+  get cookieJar() {
+    // TODO NEWAPI move _cookieJar to window probably
+    return idlUtils.implForWrapper(this[window]._document)._cookieJar;
+  }
+
+  serialize() {
+    return fragmentSerialization(idlUtils.implForWrapper(this[window]._document), { requireWellFormed: false });
+  }
+
+  nodeLocation(node) {
+    if (!idlUtils.implForWrapper(this[window]._document)._parseOptions.sourceCodeLocationInfo) {
+      throw new Error("Location information was not saved for this jsdom. Use includeNodeLocations during creation.");
+    }
+
+    return idlUtils.implForWrapper(node).sourceCodeLocation;
+  }
+
+  getInternalVMContext() {
+    if (!vm.isContext(this[window])) {
+      throw new TypeError("This jsdom was not configured to allow script running. " +
+        "Use the runScripts option during creation.");
+    }
+
+    return this[window];
+  }
+
+  reconfigure(settings) {
+    if ("windowTop" in settings) {
+      this[window]._top = settings.windowTop;
+    }
+
+    if ("url" in settings) {
+      const document = idlUtils.implForWrapper(this[window]._document);
+
+      const url = whatwgURL.parseURL(settings.url);
+      if (url === null) {
+        throw new TypeError(`Could not parse "${settings.url}" as a URL`);
+      }
+
+      document._URL = url;
+      document._origin = whatwgURL.serializeURLOrigin(document._URL);
+    }
+  }
+
+  static fragment(string = "") {
+    if (!sharedFragmentDocument) {
+      sharedFragmentDocument = (new JSDOM()).window.document;
+    }
+
+    const template = sharedFragmentDocument.createElement("template");
+    template.innerHTML = string;
+    return template.content;
+  }
+
+  static fromURL(url, options = {}) {
+    return Promise.resolve().then(() => {
+      // Remove the hash while sending this through the research loader fetch().
+      // It gets added back a few lines down when constructing the JSDOM object.
+      const parsedURL = new URL(url);
+      const originalHash = parsedURL.hash;
+      parsedURL.hash = "";
+      url = parsedURL.href;
+
+      options = normalizeFromURLOptions(options);
+
+      const resourceLoader = resourcesToResourceLoader(options.resources);
+      const resourceLoaderForInitialRequest = resourceLoader.constructor === NoOpResourceLoader ?
+        new ResourceLoader() :
+        resourceLoader;
+
+      const req = resourceLoaderForInitialRequest.fetch(url, {
+        accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
+        cookieJar: options.cookieJar,
+        referrer: options.referrer
+      });
+
+      return req.then(body => {
+        const res = req.response;
+
+        options = Object.assign(options, {
+          url: req.href + originalHash,
+          contentType: res.headers["content-type"],
+          referrer: req.getHeader("referer")
+        });
+
+        return new JSDOM(body, options);
+      });
+    });
+  }
+
+  static async fromFile(filename, options = {}) {
+    options = normalizeFromFileOptions(filename, options);
+    const buffer = await fs.readFile(filename);
+
+    return new JSDOM(buffer, options);
+  }
+}
+
+function normalizeFromURLOptions(options) {
+  // Checks on options that are invalid for `fromURL`
+  if (options.url !== undefined) {
+    throw new TypeError("Cannot supply a url option when using fromURL");
+  }
+  if (options.contentType !== undefined) {
+    throw new TypeError("Cannot supply a contentType option when using fromURL");
+  }
+
+  // Normalization of options which must be done before the rest of the fromURL code can use them, because they are
+  // given to request()
+  const normalized = { ...options };
+
+  if (options.referrer !== undefined) {
+    normalized.referrer = (new URL(options.referrer)).href;
+  }
+
+  if (options.cookieJar === undefined) {
+    normalized.cookieJar = new CookieJar();
+  }
+
+  return normalized;
+
+  // All other options don't need to be processed yet, and can be taken care of in the normal course of things when
+  // `fromURL` calls `new JSDOM(html, options)`.
+}
+
+function normalizeFromFileOptions(filename, options) {
+  const normalized = { ...options };
+
+  if (normalized.contentType === undefined) {
+    const extname = path.extname(filename);
+    if (extname === ".xhtml" || extname === ".xht" || extname === ".xml") {
+      normalized.contentType = "application/xhtml+xml";
+    }
+  }
+
+  if (normalized.url === undefined) {
+    normalized.url = new URL("file:" + path.resolve(filename));
+  }
+
+  return normalized;
+}
+
+function transformOptions(options, encoding, mimeType) {
+  const transformed = {
+    windowOptions: {
+      // Defaults
+      url: "about:blank",
+      referrer: "",
+      contentType: "text/html",
+      parsingMode: "html",
+      parseOptions: {
+        sourceCodeLocationInfo: false,
+        scriptingEnabled: false
+      },
+      runScripts: undefined,
+      encoding,
+      pretendToBeVisual: false,
+      storageQuota: 5000000,
+
+      // Defaults filled in later
+      resourceLoader: undefined,
+      virtualConsole: undefined,
+      cookieJar: undefined
+    },
+
+    // Defaults
+    beforeParse() { }
+  };
+
+  // options.contentType was parsed into mimeType by the caller.
+  if (!mimeType.isHTML() && !mimeType.isXML()) {
+    throw new RangeError(`The given content type of "${options.contentType}" was not a HTML or XML content type`);
+  }
+
+  transformed.windowOptions.contentType = mimeType.essence;
+  transformed.windowOptions.parsingMode = mimeType.isHTML() ? "html" : "xml";
+
+  if (options.url !== undefined) {
+    transformed.windowOptions.url = (new URL(options.url)).href;
+  }
+
+  if (options.referrer !== undefined) {
+    transformed.windowOptions.referrer = (new URL(options.referrer)).href;
+  }
+
+  if (options.includeNodeLocations) {
+    if (transformed.windowOptions.parsingMode === "xml") {
+      throw new TypeError("Cannot set includeNodeLocations to true with an XML content type");
+    }
+
+    transformed.windowOptions.parseOptions = { sourceCodeLocationInfo: true };
+  }
+
+  transformed.windowOptions.cookieJar = options.cookieJar === undefined ?
+                                       new CookieJar() :
+                                       options.cookieJar;
+
+  transformed.windowOptions.virtualConsole = options.virtualConsole === undefined ?
+                                            (new VirtualConsole()).sendTo(console) :
+                                            options.virtualConsole;
+
+  if (!(transformed.windowOptions.virtualConsole instanceof VirtualConsole)) {
+    throw new TypeError("virtualConsole must be an instance of VirtualConsole");
+  }
+
+  transformed.windowOptions.resourceLoader = resourcesToResourceLoader(options.resources);
+
+  if (options.runScripts !== undefined) {
+    transformed.windowOptions.runScripts = String(options.runScripts);
+    if (transformed.windowOptions.runScripts === "dangerously") {
+      transformed.windowOptions.parseOptions.scriptingEnabled = true;
+    } else if (transformed.windowOptions.runScripts !== "outside-only") {
+      throw new RangeError(`runScripts must be undefined, "dangerously", or "outside-only"`);
+    }
+  }
+
+  if (options.beforeParse !== undefined) {
+    transformed.beforeParse = options.beforeParse;
+  }
+
+  if (options.pretendToBeVisual !== undefined) {
+    transformed.windowOptions.pretendToBeVisual = Boolean(options.pretendToBeVisual);
+  }
+
+  if (options.storageQuota !== undefined) {
+    transformed.windowOptions.storageQuota = Number(options.storageQuota);
+  }
+
+  return transformed;
+}
+
+function normalizeHTML(html, mimeType) {
+  let encoding = "UTF-8";
+
+  if (ArrayBuffer.isView(html)) {
+    html = Buffer.from(html.buffer, html.byteOffset, html.byteLength);
+  } else if (html instanceof ArrayBuffer) {
+    html = Buffer.from(html);
+  }
+
+  if (Buffer.isBuffer(html)) {
+    encoding = sniffHTMLEncoding(html, {
+      defaultEncoding: mimeType.isXML() ? "UTF-8" : "windows-1252",
+      transportLayerEncodingLabel: mimeType.parameters.get("charset")
+    });
+    html = whatwgEncoding.decode(html, encoding);
+  } else {
+    html = String(html);
+  }
+
+  return { html, encoding };
+}
+
+function resourcesToResourceLoader(resources) {
+  switch (resources) {
+    case undefined: {
+      return new NoOpResourceLoader();
+    }
+    case "usable": {
+      return new ResourceLoader();
+    }
+    default: {
+      if (!(resources instanceof ResourceLoader)) {
+        throw new TypeError("resources must be an instance of ResourceLoader");
+      }
+      return resources;
+    }
+  }
+}
+
+exports.JSDOM = JSDOM;
+
+exports.VirtualConsole = VirtualConsole;
+exports.CookieJar = CookieJar;
+exports.ResourceLoader = ResourceLoader;
+
+exports.toughCookie = toughCookie;
Index: frontend/node_modules/jsdom/lib/jsdom/browser/Window.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/Window.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/Window.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,933 @@
+"use strict";
+const vm = require("vm");
+const webIDLConversions = require("webidl-conversions");
+const { CSSStyleDeclaration } = require("cssstyle");
+const { Performance: RawPerformance } = require("w3c-hr-time");
+const notImplemented = require("./not-implemented");
+const { installInterfaces } = require("../living/interfaces");
+const { define, mixin } = require("../utils");
+const Element = require("../living/generated/Element");
+const EventTarget = require("../living/generated/EventTarget");
+const EventHandlerNonNull = require("../living/generated/EventHandlerNonNull");
+const OnBeforeUnloadEventHandlerNonNull = require("../living/generated/OnBeforeUnloadEventHandlerNonNull");
+const OnErrorEventHandlerNonNull = require("../living/generated/OnErrorEventHandlerNonNull");
+const PageTransitionEvent = require("../living/generated/PageTransitionEvent");
+const namedPropertiesWindow = require("../living/named-properties-window");
+const postMessage = require("../living/post-message");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { btoa, atob } = require("abab");
+const idlUtils = require("../living/generated/utils");
+const WebSocketImpl = require("../living/websockets/WebSocket-impl").implementation;
+const BarProp = require("../living/generated/BarProp");
+const documents = require("../living/documents.js");
+const External = require("../living/generated/External");
+const Navigator = require("../living/generated/Navigator");
+const Performance = require("../living/generated/Performance");
+const Screen = require("../living/generated/Screen");
+const Storage = require("../living/generated/Storage");
+const Selection = require("../living/generated/Selection");
+const reportException = require("../living/helpers/runtime-script-errors");
+const { getCurrentEventHandlerValue } = require("../living/helpers/create-event-accessor.js");
+const { fireAnEvent } = require("../living/helpers/events");
+const SessionHistory = require("../living/window/SessionHistory");
+const { forEachMatchingSheetRuleOfElement, getResolvedValue, propertiesWithResolvedValueImplemented,
+  SHADOW_DOM_PSEUDO_REGEXP } = require("../living/helpers/style-rules.js");
+const CustomElementRegistry = require("../living/generated/CustomElementRegistry");
+const jsGlobals = require("./js-globals.json");
+
+const GlobalEventHandlersImpl = require("../living/nodes/GlobalEventHandlers-impl").implementation;
+const WindowEventHandlersImpl = require("../living/nodes/WindowEventHandlers-impl").implementation;
+
+const events = new Set([
+  // GlobalEventHandlers
+  "abort", "autocomplete",
+  "autocompleteerror", "blur",
+  "cancel", "canplay", "canplaythrough",
+  "change", "click",
+  "close", "contextmenu",
+  "cuechange", "dblclick",
+  "drag", "dragend",
+  "dragenter",
+  "dragleave", "dragover",
+  "dragstart", "drop",
+  "durationchange", "emptied",
+  "ended", "focus",
+  "input", "invalid",
+  "keydown", "keypress",
+  "keyup", "load", "loadeddata",
+  "loadedmetadata", "loadstart",
+  "mousedown", "mouseenter",
+  "mouseleave", "mousemove",
+  "mouseout", "mouseover",
+  "mouseup", "wheel",
+  "pause", "play",
+  "playing", "progress",
+  "ratechange", "reset",
+  "resize", "scroll",
+  "securitypolicyviolation",
+  "seeked", "seeking",
+  "select", "sort", "stalled",
+  "submit", "suspend",
+  "timeupdate", "toggle",
+  "volumechange", "waiting",
+
+  // WindowEventHandlers
+  "afterprint",
+  "beforeprint",
+  "hashchange",
+  "languagechange",
+  "message",
+  "messageerror",
+  "offline",
+  "online",
+  "pagehide",
+  "pageshow",
+  "popstate",
+  "rejectionhandled",
+  "storage",
+  "unhandledrejection",
+  "unload"
+
+  // "error" and "beforeunload" are added separately
+]);
+
+exports.createWindow = function (options) {
+  return new Window(options);
+};
+
+const jsGlobalEntriesToInstall = Object.entries(jsGlobals).filter(([name]) => name in global);
+
+// TODO remove when we drop Node v10 support.
+const anyNodeVersionQueueMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : process.nextTick;
+
+// https://html.spec.whatwg.org/#the-window-object
+function setupWindow(windowInstance, { runScripts }) {
+  if (runScripts === "outside-only" || runScripts === "dangerously") {
+    contextifyWindow(windowInstance);
+
+    // Without this, these globals will only appear to scripts running inside the context using vm.runScript; they will
+    // not appear to scripts running from the outside, including to JSDOM implementation code.
+    for (const [globalName, globalPropDesc] of jsGlobalEntriesToInstall) {
+      const propDesc = { ...globalPropDesc, value: vm.runInContext(globalName, windowInstance) };
+      Object.defineProperty(windowInstance, globalName, propDesc);
+    }
+  } else {
+    // Without contextifying the window, none of the globals will exist. So, let's at least alias them from the Node.js
+    // context. See https://github.com/jsdom/jsdom/issues/2727 for more background and discussion.
+    for (const [globalName, globalPropDesc] of jsGlobalEntriesToInstall) {
+      const propDesc = { ...globalPropDesc, value: global[globalName] };
+      Object.defineProperty(windowInstance, globalName, propDesc);
+    }
+  }
+
+  installInterfaces(windowInstance, ["Window"]);
+
+  const EventTargetConstructor = windowInstance.EventTarget;
+
+  // eslint-disable-next-line func-name-matching, func-style, no-shadow
+  const windowConstructor = function Window() {
+    throw new TypeError("Illegal constructor");
+  };
+  Object.setPrototypeOf(windowConstructor, EventTargetConstructor);
+
+  Object.defineProperty(windowInstance, "Window", {
+    configurable: true,
+    writable: true,
+    value: windowConstructor
+  });
+
+  const windowPrototype = Object.create(EventTargetConstructor.prototype);
+  Object.defineProperties(windowPrototype, {
+    constructor: {
+      value: windowConstructor,
+      writable: true,
+      configurable: true
+    },
+    [Symbol.toStringTag]: {
+      value: "Window",
+      configurable: true
+    }
+  });
+
+  windowConstructor.prototype = windowPrototype;
+  Object.setPrototypeOf(windowInstance, windowPrototype);
+
+  EventTarget.setup(windowInstance, windowInstance);
+  mixin(windowInstance, WindowEventHandlersImpl.prototype);
+  mixin(windowInstance, GlobalEventHandlersImpl.prototype);
+  windowInstance._initGlobalEvents();
+
+  Object.defineProperty(windowInstance, "onbeforeunload", {
+    configurable: true,
+    enumerable: true,
+    get() {
+      return idlUtils.tryWrapperForImpl(getCurrentEventHandlerValue(this, "beforeunload"));
+    },
+    set(V) {
+      if (!idlUtils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnBeforeUnloadEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeunload' property on 'Window': The provided value"
+        });
+      }
+      this._setEventHandlerFor("beforeunload", V);
+    }
+  });
+
+  Object.defineProperty(windowInstance, "onerror", {
+    configurable: true,
+    enumerable: true,
+    get() {
+      return idlUtils.tryWrapperForImpl(getCurrentEventHandlerValue(this, "error"));
+    },
+    set(V) {
+      if (!idlUtils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnErrorEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'Window': The provided value"
+        });
+      }
+      this._setEventHandlerFor("error", V);
+    }
+  });
+
+  for (const event of events) {
+    Object.defineProperty(windowInstance, `on${event}`, {
+      configurable: true,
+      enumerable: true,
+      get() {
+        return idlUtils.tryWrapperForImpl(getCurrentEventHandlerValue(this, event));
+      },
+      set(V) {
+        if (!idlUtils.isObject(V)) {
+          V = null;
+        } else {
+          V = EventHandlerNonNull.convert(V, {
+            context: `Failed to set the 'on${event}' property on 'Window': The provided value`
+          });
+        }
+        this._setEventHandlerFor(event, V);
+      }
+    });
+  }
+
+  windowInstance._globalObject = windowInstance;
+}
+
+// NOTE: per https://heycam.github.io/webidl/#Global, all properties on the Window object must be own-properties.
+// That is why we assign everything inside of the constructor, instead of using a shared prototype.
+// You can verify this in e.g. Firefox or Internet Explorer, which do a good job with Web IDL compliance.
+function Window(options) {
+  setupWindow(this, { runScripts: options.runScripts });
+
+  const rawPerformance = new RawPerformance();
+  const windowInitialized = rawPerformance.now();
+
+  const window = this;
+
+  // ### PRIVATE DATA PROPERTIES
+
+  this._resourceLoader = options.resourceLoader;
+
+  // vm initialization is deferred until script processing is activated
+  this._globalProxy = this;
+  Object.defineProperty(idlUtils.implForWrapper(this), idlUtils.wrapperSymbol, { get: () => this._globalProxy });
+
+  // List options explicitly to be clear which are passed through
+  this._document = documents.createWrapper(window, {
+    parsingMode: options.parsingMode,
+    contentType: options.contentType,
+    encoding: options.encoding,
+    cookieJar: options.cookieJar,
+    url: options.url,
+    lastModified: options.lastModified,
+    referrer: options.referrer,
+    parseOptions: options.parseOptions,
+    defaultView: this._globalProxy,
+    global: this,
+    parentOrigin: options.parentOrigin
+  }, { alwaysUseDocumentClass: true });
+
+  if (vm.isContext(window)) {
+    const documentImpl = idlUtils.implForWrapper(window._document);
+    documentImpl._defaultView = window._globalProxy = vm.runInContext("this", window);
+  }
+
+  const documentOrigin = idlUtils.implForWrapper(this._document)._origin;
+  this._origin = documentOrigin;
+
+  // https://html.spec.whatwg.org/#session-history
+  this._sessionHistory = new SessionHistory({
+    document: idlUtils.implForWrapper(this._document),
+    url: idlUtils.implForWrapper(this._document)._URL,
+    stateObject: null
+  }, this);
+
+  this._virtualConsole = options.virtualConsole;
+
+  this._runScripts = options.runScripts;
+
+  // Set up the window as if it's a top level window.
+  // If it's not, then references will be corrected by frame/iframe code.
+  this._parent = this._top = this._globalProxy;
+  this._frameElement = null;
+
+  // This implements window.frames.length, since window.frames returns a
+  // self reference to the window object.  This value is incremented in the
+  // HTMLFrameElement implementation.
+  this._length = 0;
+
+  // https://dom.spec.whatwg.org/#window-current-event
+  this._currentEvent = undefined;
+
+  this._pretendToBeVisual = options.pretendToBeVisual;
+  this._storageQuota = options.storageQuota;
+
+  // Some properties (such as localStorage and sessionStorage) share data
+  // between windows in the same origin. This object is intended
+  // to contain such data.
+  if (options.commonForOrigin && options.commonForOrigin[documentOrigin]) {
+    this._commonForOrigin = options.commonForOrigin;
+  } else {
+    this._commonForOrigin = {
+      [documentOrigin]: {
+        localStorageArea: new Map(),
+        sessionStorageArea: new Map(),
+        windowsInSameOrigin: [this]
+      }
+    };
+  }
+
+  this._currentOriginData = this._commonForOrigin[documentOrigin];
+
+  // ### WEB STORAGE
+
+  this._localStorage = Storage.create(window, [], {
+    associatedWindow: this,
+    storageArea: this._currentOriginData.localStorageArea,
+    type: "localStorage",
+    url: this._document.documentURI,
+    storageQuota: this._storageQuota
+  });
+  this._sessionStorage = Storage.create(window, [], {
+    associatedWindow: this,
+    storageArea: this._currentOriginData.sessionStorageArea,
+    type: "sessionStorage",
+    url: this._document.documentURI,
+    storageQuota: this._storageQuota
+  });
+
+  // ### SELECTION
+
+  // https://w3c.github.io/selection-api/#dfn-selection
+  this._selection = Selection.createImpl(window);
+
+  // https://w3c.github.io/selection-api/#dom-window
+  this.getSelection = function () {
+    return window._selection;
+  };
+
+  // ### GETTERS
+
+  const locationbar = BarProp.create(window);
+  const menubar = BarProp.create(window);
+  const personalbar = BarProp.create(window);
+  const scrollbars = BarProp.create(window);
+  const statusbar = BarProp.create(window);
+  const toolbar = BarProp.create(window);
+  const external = External.create(window);
+  const navigator = Navigator.create(window, [], { userAgent: this._resourceLoader._userAgent });
+  const performance = Performance.create(window, [], { rawPerformance });
+  const screen = Screen.create(window);
+  const customElementRegistry = CustomElementRegistry.create(window);
+
+  define(this, {
+    get length() {
+      return window._length;
+    },
+    get window() {
+      return window._globalProxy;
+    },
+    get frameElement() {
+      return idlUtils.wrapperForImpl(window._frameElement);
+    },
+    get frames() {
+      return window._globalProxy;
+    },
+    get self() {
+      return window._globalProxy;
+    },
+    get parent() {
+      return window._parent;
+    },
+    get top() {
+      return window._top;
+    },
+    get document() {
+      return window._document;
+    },
+    get external() {
+      return external;
+    },
+    get location() {
+      return idlUtils.wrapperForImpl(idlUtils.implForWrapper(window._document)._location);
+    },
+    get history() {
+      return idlUtils.wrapperForImpl(idlUtils.implForWrapper(window._document)._history);
+    },
+    get navigator() {
+      return navigator;
+    },
+    get locationbar() {
+      return locationbar;
+    },
+    get menubar() {
+      return menubar;
+    },
+    get personalbar() {
+      return personalbar;
+    },
+    get scrollbars() {
+      return scrollbars;
+    },
+    get statusbar() {
+      return statusbar;
+    },
+    get toolbar() {
+      return toolbar;
+    },
+    get performance() {
+      return performance;
+    },
+    get screen() {
+      return screen;
+    },
+    get origin() {
+      return window._origin;
+    },
+    // The origin IDL attribute is defined with [Replaceable].
+    set origin(value) {
+      Object.defineProperty(this, "origin", {
+        value,
+        writable: true,
+        enumerable: true,
+        configurable: true
+      });
+    },
+    get localStorage() {
+      if (idlUtils.implForWrapper(this._document)._origin === "null") {
+        throw DOMException.create(window, [
+          "localStorage is not available for opaque origins",
+          "SecurityError"
+        ]);
+      }
+
+      return this._localStorage;
+    },
+    get sessionStorage() {
+      if (idlUtils.implForWrapper(this._document)._origin === "null") {
+        throw DOMException.create(window, [
+          "sessionStorage is not available for opaque origins",
+          "SecurityError"
+        ]);
+      }
+
+      return this._sessionStorage;
+    },
+    get customElements() {
+      return customElementRegistry;
+    },
+    get event() {
+      return window._currentEvent ? idlUtils.wrapperForImpl(window._currentEvent) : undefined;
+    },
+    set event(value) {
+      Object.defineProperty(window, "event", { configurable: true, enumerable: true, writable: true, value });
+    }
+  });
+
+  namedPropertiesWindow.initializeWindow(this, this._globalProxy);
+
+  // ### METHODS
+
+  // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
+
+  // In the spec the list of active timers is a set of IDs. We make it a map of IDs to Node.js timer objects, so that
+  // we can call Node.js-side clearTimeout() when clearing, and thus allow process shutdown faster.
+  const listOfActiveTimers = new Map();
+  let latestTimerId = 0;
+
+  this.setTimeout = function (handler, timeout = 0, ...args) {
+    if (typeof handler !== "function") {
+      handler = webIDLConversions.DOMString(handler);
+    }
+    timeout = webIDLConversions.long(timeout);
+
+    return timerInitializationSteps(handler, timeout, args, { methodContext: window, repeat: false });
+  };
+  this.setInterval = function (handler, timeout = 0, ...args) {
+    if (typeof handler !== "function") {
+      handler = webIDLConversions.DOMString(handler);
+    }
+    timeout = webIDLConversions.long(timeout);
+
+    return timerInitializationSteps(handler, timeout, args, { methodContext: window, repeat: true });
+  };
+
+  this.clearTimeout = function (handle = 0) {
+    handle = webIDLConversions.long(handle);
+
+    const nodejsTimer = listOfActiveTimers.get(handle);
+    if (nodejsTimer) {
+      clearTimeout(nodejsTimer);
+      listOfActiveTimers.delete(handle);
+    }
+  };
+  this.clearInterval = function (handle = 0) {
+    handle = webIDLConversions.long(handle);
+
+    const nodejsTimer = listOfActiveTimers.get(handle);
+    if (nodejsTimer) {
+      // We use setTimeout() in timerInitializationSteps even for this.setInterval().
+      clearTimeout(nodejsTimer);
+      listOfActiveTimers.delete(handle);
+    }
+  };
+
+  function timerInitializationSteps(handler, timeout, args, { methodContext, repeat, previousHandle }) {
+    // This appears to be unspecced, but matches browser behavior for close()ed windows.
+    if (!methodContext._document) {
+      return 0;
+    }
+
+    // TODO: implement timer nesting level behavior.
+
+    const methodContextProxy = methodContext._globalProxy;
+    const handle = previousHandle !== undefined ? previousHandle : ++latestTimerId;
+
+    function task() {
+      if (!listOfActiveTimers.has(handle)) {
+        return;
+      }
+
+      try {
+        if (typeof handler === "function") {
+          handler.apply(methodContextProxy, args);
+        } else if (window._runScripts === "dangerously") {
+          vm.runInContext(handler, window, { filename: window.location.href, displayErrors: false });
+        }
+      } catch (e) {
+        reportException(window, e, window.location.href);
+      }
+
+      if (listOfActiveTimers.has(handle)) {
+        if (repeat) {
+          timerInitializationSteps(handler, timeout, args, { methodContext, repeat: true, previousHandle: handle });
+        } else {
+          listOfActiveTimers.delete(handle);
+        }
+      }
+    }
+
+    if (timeout < 0) {
+      timeout = 0;
+    }
+
+    const nodejsTimer = setTimeout(task, timeout);
+    listOfActiveTimers.set(handle, nodejsTimer);
+
+    return handle;
+  }
+
+  // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#microtask-queuing
+
+  this.queueMicrotask = function (callback) {
+    callback = webIDLConversions.Function(callback);
+
+    anyNodeVersionQueueMicrotask(() => {
+      try {
+        callback();
+      } catch (e) {
+        reportException(window, e, window.location.href);
+      }
+    });
+  };
+
+  // https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frames
+
+  let animationFrameCallbackId = 0;
+  const mapOfAnimationFrameCallbacks = new Map();
+  let animationFrameNodejsInterval = null;
+
+  // Unlike the spec, where an animation frame happens every 60 Hz regardless, we optimize so that if there are no
+  // requestAnimationFrame() calls outstanding, we don't fire the timer. This helps us track that.
+  let numberOfOngoingAnimationFrameCallbacks = 0;
+
+  if (this._pretendToBeVisual) {
+    this.requestAnimationFrame = function (callback) {
+      callback = webIDLConversions.Function(callback);
+
+      const handle = ++animationFrameCallbackId;
+      mapOfAnimationFrameCallbacks.set(handle, callback);
+
+      ++numberOfOngoingAnimationFrameCallbacks;
+      if (numberOfOngoingAnimationFrameCallbacks === 1) {
+        animationFrameNodejsInterval = setInterval(() => {
+          runAnimationFrameCallbacks(rawPerformance.now() - windowInitialized);
+        }, 1000 / 60);
+      }
+
+      return handle;
+    };
+
+    this.cancelAnimationFrame = function (handle) {
+      handle = webIDLConversions["unsigned long"](handle);
+
+      removeAnimationFrameCallback(handle);
+    };
+
+    function runAnimationFrameCallbacks(now) {
+      // Converting to an array is important to get a sync snapshot and thus match spec semantics.
+      const callbackHandles = [...mapOfAnimationFrameCallbacks.keys()];
+      for (const handle of callbackHandles) {
+        // This has() can be false if a callback calls cancelAnimationFrame().
+        if (mapOfAnimationFrameCallbacks.has(handle)) {
+          const callback = mapOfAnimationFrameCallbacks.get(handle);
+          removeAnimationFrameCallback(handle);
+          try {
+            callback(now);
+          } catch (e) {
+            reportException(window, e, window.location.href);
+          }
+        }
+      }
+    }
+
+    function removeAnimationFrameCallback(handle) {
+      if (mapOfAnimationFrameCallbacks.has(handle)) {
+        --numberOfOngoingAnimationFrameCallbacks;
+        if (numberOfOngoingAnimationFrameCallbacks === 0) {
+          clearInterval(animationFrameNodejsInterval);
+        }
+      }
+
+      mapOfAnimationFrameCallbacks.delete(handle);
+    }
+  }
+
+  function stopAllTimers() {
+    for (const nodejsTimer of listOfActiveTimers.values()) {
+      clearTimeout(nodejsTimer);
+    }
+    listOfActiveTimers.clear();
+
+    clearInterval(animationFrameNodejsInterval);
+  }
+
+  function Option(text, value, defaultSelected, selected) {
+    if (text === undefined) {
+      text = "";
+    }
+    text = webIDLConversions.DOMString(text);
+
+    if (value !== undefined) {
+      value = webIDLConversions.DOMString(value);
+    }
+
+    defaultSelected = webIDLConversions.boolean(defaultSelected);
+    selected = webIDLConversions.boolean(selected);
+
+    const option = window._document.createElement("option");
+    const impl = idlUtils.implForWrapper(option);
+
+    if (text !== "") {
+      impl.text = text;
+    }
+    if (value !== undefined) {
+      impl.setAttributeNS(null, "value", value);
+    }
+    if (defaultSelected) {
+      impl.setAttributeNS(null, "selected", "");
+    }
+    impl._selectedness = selected;
+
+    return option;
+  }
+  Object.defineProperty(Option, "prototype", {
+    value: this.HTMLOptionElement.prototype,
+    configurable: false,
+    enumerable: false,
+    writable: false
+  });
+  Object.defineProperty(window, "Option", {
+    value: Option,
+    configurable: true,
+    enumerable: false,
+    writable: true
+  });
+
+  function Image(...args) {
+    const img = window._document.createElement("img");
+    const impl = idlUtils.implForWrapper(img);
+
+    if (args.length > 0) {
+      impl.setAttributeNS(null, "width", String(args[0]));
+    }
+    if (args.length > 1) {
+      impl.setAttributeNS(null, "height", String(args[1]));
+    }
+
+    return img;
+  }
+  Object.defineProperty(Image, "prototype", {
+    value: this.HTMLImageElement.prototype,
+    configurable: false,
+    enumerable: false,
+    writable: false
+  });
+  Object.defineProperty(window, "Image", {
+    value: Image,
+    configurable: true,
+    enumerable: false,
+    writable: true
+  });
+
+  function Audio(src) {
+    const audio = window._document.createElement("audio");
+    const impl = idlUtils.implForWrapper(audio);
+    impl.setAttributeNS(null, "preload", "auto");
+
+    if (src !== undefined) {
+      impl.setAttributeNS(null, "src", String(src));
+    }
+
+    return audio;
+  }
+  Object.defineProperty(Audio, "prototype", {
+    value: this.HTMLAudioElement.prototype,
+    configurable: false,
+    enumerable: false,
+    writable: false
+  });
+  Object.defineProperty(window, "Audio", {
+    value: Audio,
+    configurable: true,
+    enumerable: false,
+    writable: true
+  });
+
+  this.postMessage = postMessage(window);
+
+  this.atob = function (str) {
+    const result = atob(str);
+    if (result === null) {
+      throw DOMException.create(window, [
+        "The string to be decoded contains invalid characters.",
+        "InvalidCharacterError"
+      ]);
+    }
+    return result;
+  };
+
+  this.btoa = function (str) {
+    const result = btoa(str);
+    if (result === null) {
+      throw DOMException.create(window, [
+        "The string to be encoded contains invalid characters.",
+        "InvalidCharacterError"
+      ]);
+    }
+    return result;
+  };
+
+  this.stop = function () {
+    const manager = idlUtils.implForWrapper(this._document)._requestManager;
+    if (manager) {
+      manager.close();
+    }
+  };
+
+  this.close = function () {
+    // Recursively close child frame windows, then ourselves (depth-first).
+    for (let i = 0; i < this.length; ++i) {
+      this[i].close();
+    }
+
+    // Clear out all listeners. Any in-flight or upcoming events should not get delivered.
+    idlUtils.implForWrapper(this)._eventListeners = Object.create(null);
+
+    if (this._document) {
+      if (this._document.body) {
+        this._document.body.innerHTML = "";
+      }
+
+      if (this._document.close) {
+        // It's especially important to clear out the listeners here because document.close() causes a "load" event to
+        // fire.
+        idlUtils.implForWrapper(this._document)._eventListeners = Object.create(null);
+        this._document.close();
+      }
+      const doc = idlUtils.implForWrapper(this._document);
+      if (doc._requestManager) {
+        doc._requestManager.close();
+      }
+      delete this._document;
+    }
+
+    stopAllTimers();
+    WebSocketImpl.cleanUpWindow(this);
+  };
+
+  this.getComputedStyle = function (elt, pseudoElt = undefined) {
+    elt = Element.convert(elt);
+    if (pseudoElt !== undefined && pseudoElt !== null) {
+      pseudoElt = webIDLConversions.DOMString(pseudoElt);
+    }
+
+    if (pseudoElt !== undefined && pseudoElt !== null && pseudoElt !== "") {
+      // TODO: Parse pseudoElt
+
+      if (SHADOW_DOM_PSEUDO_REGEXP.test(pseudoElt)) {
+        throw new TypeError("Tried to get the computed style of a Shadow DOM pseudo-element.");
+      }
+
+      notImplemented("window.computedStyle(elt, pseudoElt)", this);
+    }
+
+    const declaration = new CSSStyleDeclaration();
+    const { forEach } = Array.prototype;
+    const { style } = elt;
+
+    forEachMatchingSheetRuleOfElement(elt, rule => {
+      forEach.call(rule.style, property => {
+        declaration.setProperty(
+          property,
+          rule.style.getPropertyValue(property),
+          rule.style.getPropertyPriority(property)
+        );
+      });
+    });
+
+    // https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle
+    const declarations = Object.keys(propertiesWithResolvedValueImplemented);
+    forEach.call(declarations, property => {
+      declaration.setProperty(property, getResolvedValue(elt, property));
+    });
+
+    forEach.call(style, property => {
+      declaration.setProperty(property, style.getPropertyValue(property), style.getPropertyPriority(property));
+    });
+
+    return declaration;
+  };
+
+  this.getSelection = function () {
+    return window._document.getSelection();
+  };
+
+  // The captureEvents() and releaseEvents() methods must do nothing
+  this.captureEvents = function () {};
+
+  this.releaseEvents = function () {};
+
+  // ### PUBLIC DATA PROPERTIES (TODO: should be getters)
+
+  function wrapConsoleMethod(method) {
+    return (...args) => {
+      window._virtualConsole.emit(method, ...args);
+    };
+  }
+
+  this.console = {
+    assert: wrapConsoleMethod("assert"),
+    clear: wrapConsoleMethod("clear"),
+    count: wrapConsoleMethod("count"),
+    countReset: wrapConsoleMethod("countReset"),
+    debug: wrapConsoleMethod("debug"),
+    dir: wrapConsoleMethod("dir"),
+    dirxml: wrapConsoleMethod("dirxml"),
+    error: wrapConsoleMethod("error"),
+    group: wrapConsoleMethod("group"),
+    groupCollapsed: wrapConsoleMethod("groupCollapsed"),
+    groupEnd: wrapConsoleMethod("groupEnd"),
+    info: wrapConsoleMethod("info"),
+    log: wrapConsoleMethod("log"),
+    table: wrapConsoleMethod("table"),
+    time: wrapConsoleMethod("time"),
+    timeLog: wrapConsoleMethod("timeLog"),
+    timeEnd: wrapConsoleMethod("timeEnd"),
+    trace: wrapConsoleMethod("trace"),
+    warn: wrapConsoleMethod("warn")
+  };
+
+  function notImplementedMethod(name) {
+    return function () {
+      notImplemented(name, window);
+    };
+  }
+
+  define(this, {
+    name: "",
+    status: "",
+    devicePixelRatio: 1,
+    innerWidth: 1024,
+    innerHeight: 768,
+    outerWidth: 1024,
+    outerHeight: 768,
+    pageXOffset: 0,
+    pageYOffset: 0,
+    screenX: 0,
+    screenLeft: 0,
+    screenY: 0,
+    screenTop: 0,
+    scrollX: 0,
+    scrollY: 0,
+
+    alert: notImplementedMethod("window.alert"),
+    blur: notImplementedMethod("window.blur"),
+    confirm: notImplementedMethod("window.confirm"),
+    focus: notImplementedMethod("window.focus"),
+    moveBy: notImplementedMethod("window.moveBy"),
+    moveTo: notImplementedMethod("window.moveTo"),
+    open: notImplementedMethod("window.open"),
+    print: notImplementedMethod("window.print"),
+    prompt: notImplementedMethod("window.prompt"),
+    resizeBy: notImplementedMethod("window.resizeBy"),
+    resizeTo: notImplementedMethod("window.resizeTo"),
+    scroll: notImplementedMethod("window.scroll"),
+    scrollBy: notImplementedMethod("window.scrollBy"),
+    scrollTo: notImplementedMethod("window.scrollTo")
+  });
+
+  // ### INITIALIZATION
+
+  process.nextTick(() => {
+    if (!window.document) {
+      return; // window might've been closed already
+    }
+
+    const documentImpl = idlUtils.implForWrapper(window._document);
+
+    if (window.document.readyState === "complete") {
+      fireAnEvent("load", window, undefined, {}, documentImpl);
+    } else {
+      window.document.addEventListener("load", () => {
+        fireAnEvent("load", window, undefined, {}, documentImpl);
+
+        if (!documentImpl._pageShowingFlag) {
+          documentImpl._pageShowingFlag = true;
+          fireAnEvent("pageshow", window, PageTransitionEvent, { persisted: false }, documentImpl);
+        }
+      });
+    }
+  });
+}
+
+function contextifyWindow(window) {
+  if (vm.isContext(window)) {
+    return;
+  }
+
+  vm.createContext(window);
+}
Index: frontend/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,789 @@
+// Ideally, we would use
+// https://html.spec.whatwg.org/multipage/rendering.html#the-css-user-agent-style-sheet-and-presentational-hints
+// but for now, just use the version from blink. This file is copied from
+// https://chromium.googlesource.com/chromium/blink/+/96aa3a280ab7d67178c8f122a04949ce5f8579e0/Source/core/css/html.css
+// (removed a line which had octal literals inside since octal literals are not allowed in template strings)
+
+// We use a .js file because otherwise we can't browserify this. (brfs is unusable due to lack of ES2015 support)
+
+module.exports = `
+/*
+ * The default style sheet used to render HTML.
+ *
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+@namespace "http://www.w3.org/1999/xhtml";
+
+html {
+    display: block
+}
+
+:root {
+    scroll-blocks-on: start-touch wheel-event
+}
+
+/* children of the <head> element all have display:none */
+head {
+    display: none
+}
+
+meta {
+    display: none
+}
+
+title {
+    display: none
+}
+
+link {
+    display: none
+}
+
+style {
+    display: none
+}
+
+script {
+    display: none
+}
+
+/* generic block-level elements */
+
+body {
+    display: block;
+    margin: 8px
+}
+
+p {
+    display: block;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1__qem;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+}
+
+div {
+    display: block
+}
+
+layer {
+    display: block
+}
+
+article, aside, footer, header, hgroup, main, nav, section {
+    display: block
+}
+
+marquee {
+    display: inline-block;
+}
+
+address {
+    display: block
+}
+
+blockquote {
+    display: block;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1em;
+    -webkit-margin-start: 40px;
+    -webkit-margin-end: 40px;
+}
+
+figcaption {
+    display: block
+}
+
+figure {
+    display: block;
+    -webkit-margin-before: 1em;
+    -webkit-margin-after: 1em;
+    -webkit-margin-start: 40px;
+    -webkit-margin-end: 40px;
+}
+
+q {
+    display: inline
+}
+
+/* nwmatcher does not support ::before and ::after, so we can't render q
+correctly: https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3
+TODO: add q::before and q::after selectors
+*/
+
+center {
+    display: block;
+    /* special centering to be able to emulate the html4/netscape behaviour */
+    text-align: -webkit-center
+}
+
+hr {
+    display: block;
+    -webkit-margin-before: 0.5em;
+    -webkit-margin-after: 0.5em;
+    -webkit-margin-start: auto;
+    -webkit-margin-end: auto;
+    border-style: inset;
+    border-width: 1px;
+    box-sizing: border-box
+}
+
+map {
+    display: inline
+}
+
+video {
+    object-fit: contain;
+}
+
+/* heading elements */
+
+h1 {
+    display: block;
+    font-size: 2em;
+    -webkit-margin-before: 0.67__qem;
+    -webkit-margin-after: 0.67em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    font-weight: bold
+}
+
+article h1,
+aside h1,
+nav h1,
+section h1 {
+    font-size: 1.5em;
+    -webkit-margin-before: 0.83__qem;
+    -webkit-margin-after: 0.83em;
+}
+
+article article h1,
+article aside h1,
+article nav h1,
+article section h1,
+aside article h1,
+aside aside h1,
+aside nav h1,
+aside section h1,
+nav article h1,
+nav aside h1,
+nav nav h1,
+nav section h1,
+section article h1,
+section aside h1,
+section nav h1,
+section section h1 {
+    font-size: 1.17em;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1em;
+}
+
+/* Remaining selectors are deleted because nwmatcher does not support
+:matches() and expanding the selectors manually would be far too verbose.
+Also see https://html.spec.whatwg.org/multipage/rendering.html#sections-and-headings
+TODO: rewrite to use :matches() when nwmatcher supports it.
+*/
+
+h2 {
+    display: block;
+    font-size: 1.5em;
+    -webkit-margin-before: 0.83__qem;
+    -webkit-margin-after: 0.83em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    font-weight: bold
+}
+
+h3 {
+    display: block;
+    font-size: 1.17em;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    font-weight: bold
+}
+
+h4 {
+    display: block;
+    -webkit-margin-before: 1.33__qem;
+    -webkit-margin-after: 1.33em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    font-weight: bold
+}
+
+h5 {
+    display: block;
+    font-size: .83em;
+    -webkit-margin-before: 1.67__qem;
+    -webkit-margin-after: 1.67em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    font-weight: bold
+}
+
+h6 {
+    display: block;
+    font-size: .67em;
+    -webkit-margin-before: 2.33__qem;
+    -webkit-margin-after: 2.33em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    font-weight: bold
+}
+
+/* tables */
+
+table {
+    display: table;
+    border-collapse: separate;
+    border-spacing: 2px;
+    border-color: gray
+}
+
+thead {
+    display: table-header-group;
+    vertical-align: middle;
+    border-color: inherit
+}
+
+tbody {
+    display: table-row-group;
+    vertical-align: middle;
+    border-color: inherit
+}
+
+tfoot {
+    display: table-footer-group;
+    vertical-align: middle;
+    border-color: inherit
+}
+
+/* for tables without table section elements (can happen with XHTML or dynamically created tables) */
+table > tr {
+    vertical-align: middle;
+}
+
+col {
+    display: table-column
+}
+
+colgroup {
+    display: table-column-group
+}
+
+tr {
+    display: table-row;
+    vertical-align: inherit;
+    border-color: inherit
+}
+
+td, th {
+    display: table-cell;
+    vertical-align: inherit
+}
+
+th {
+    font-weight: bold
+}
+
+caption {
+    display: table-caption;
+    text-align: -webkit-center
+}
+
+/* lists */
+
+ul, menu, dir {
+    display: block;
+    list-style-type: disc;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    -webkit-padding-start: 40px
+}
+
+ol {
+    display: block;
+    list-style-type: decimal;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+    -webkit-padding-start: 40px
+}
+
+li {
+    display: list-item;
+    text-align: -webkit-match-parent;
+}
+
+ul ul, ol ul {
+    list-style-type: circle
+}
+
+ol ol ul, ol ul ul, ul ol ul, ul ul ul {
+    list-style-type: square
+}
+
+dd {
+    display: block;
+    -webkit-margin-start: 40px
+}
+
+dl {
+    display: block;
+    -webkit-margin-before: 1__qem;
+    -webkit-margin-after: 1em;
+    -webkit-margin-start: 0;
+    -webkit-margin-end: 0;
+}
+
+dt {
+    display: block
+}
+
+ol ul, ul ol, ul ul, ol ol {
+    -webkit-margin-before: 0;
+    -webkit-margin-after: 0
+}
+
+/* form elements */
+
+form {
+    display: block;
+    margin-top: 0__qem;
+}
+
+label {
+    cursor: default;
+}
+
+legend {
+    display: block;
+    -webkit-padding-start: 2px;
+    -webkit-padding-end: 2px;
+    border: none
+}
+
+fieldset {
+    display: block;
+    -webkit-margin-start: 2px;
+    -webkit-margin-end: 2px;
+    -webkit-padding-before: 0.35em;
+    -webkit-padding-start: 0.75em;
+    -webkit-padding-end: 0.75em;
+    -webkit-padding-after: 0.625em;
+    border: 2px groove ThreeDFace;
+    min-width: -webkit-min-content;
+}
+
+button {
+    -webkit-appearance: button;
+}
+
+/* Form controls don't go vertical. */
+input, textarea, select, button, meter, progress {
+    -webkit-writing-mode: horizontal-tb !important;
+}
+
+input, textarea, select, button {
+    margin: 0__qem;
+    font: -webkit-small-control;
+    text-rendering: auto; /* FIXME: Remove when tabs work with optimizeLegibility. */
+    color: initial;
+    letter-spacing: normal;
+    word-spacing: normal;
+    line-height: normal;
+    text-transform: none;
+    text-indent: 0;
+    text-shadow: none;
+    display: inline-block;
+    text-align: start;
+}
+
+/* TODO: Add " i" to attribute matchers to support case-insensitive matching */
+input[type="hidden"] {
+    display: none
+}
+
+input {
+    -webkit-appearance: textfield;
+    padding: 1px;
+    background-color: white;
+    border: 2px inset;
+    -webkit-rtl-ordering: logical;
+    -webkit-user-select: text;
+    cursor: auto;
+}
+
+input[type="search"] {
+    -webkit-appearance: searchfield;
+    box-sizing: border-box;
+}
+
+select {
+    border-radius: 5px;
+}
+
+textarea {
+    -webkit-appearance: textarea;
+    background-color: white;
+    border: 1px solid;
+    -webkit-rtl-ordering: logical;
+    -webkit-user-select: text;
+    flex-direction: column;
+    resize: auto;
+    cursor: auto;
+    padding: 2px;
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+
+input[type="password"] {
+    -webkit-text-security: disc !important;
+}
+
+input[type="hidden"], input[type="image"], input[type="file"] {
+    -webkit-appearance: initial;
+    padding: initial;
+    background-color: initial;
+    border: initial;
+}
+
+input[type="file"] {
+    align-items: baseline;
+    color: inherit;
+    text-align: start !important;
+}
+
+input[type="radio"], input[type="checkbox"] {
+    margin: 3px 0.5ex;
+    padding: initial;
+    background-color: initial;
+    border: initial;
+}
+
+input[type="button"], input[type="submit"], input[type="reset"] {
+    -webkit-appearance: push-button;
+    -webkit-user-select: none;
+    white-space: pre
+}
+
+input[type="button"], input[type="submit"], input[type="reset"], button {
+    align-items: flex-start;
+    text-align: center;
+    cursor: default;
+    color: ButtonText;
+    padding: 2px 6px 3px 6px;
+    border: 2px outset ButtonFace;
+    background-color: ButtonFace;
+    box-sizing: border-box
+}
+
+input[type="range"] {
+    -webkit-appearance: slider-horizontal;
+    padding: initial;
+    border: initial;
+    margin: 2px;
+    color: #909090;
+}
+
+input[type="button"]:disabled, input[type="submit"]:disabled, input[type="reset"]:disabled,
+button:disabled, select:disabled, optgroup:disabled, option:disabled,
+select[disabled]>option {
+    color: GrayText
+}
+
+input[type="button"]:active, input[type="submit"]:active, input[type="reset"]:active, button:active {
+    border-style: inset
+}
+
+input[type="button"]:active:disabled, input[type="submit"]:active:disabled, input[type="reset"]:active:disabled, button:active:disabled {
+    border-style: outset
+}
+
+datalist {
+    display: none
+}
+
+area {
+    display: inline;
+    cursor: pointer;
+}
+
+param {
+    display: none
+}
+
+input[type="checkbox"] {
+    -webkit-appearance: checkbox;
+    box-sizing: border-box;
+}
+
+input[type="radio"] {
+    -webkit-appearance: radio;
+    box-sizing: border-box;
+}
+
+input[type="color"] {
+    -webkit-appearance: square-button;
+    width: 44px;
+    height: 23px;
+    background-color: ButtonFace;
+    /* Same as native_theme_base. */
+    border: 1px #a9a9a9 solid;
+    padding: 1px 2px;
+}
+
+input[type="color"][list] {
+    -webkit-appearance: menulist;
+    width: 88px;
+    height: 23px
+}
+
+select {
+    -webkit-appearance: menulist;
+    box-sizing: border-box;
+    align-items: center;
+    border: 1px solid;
+    white-space: pre;
+    -webkit-rtl-ordering: logical;
+    color: black;
+    background-color: white;
+    cursor: default;
+}
+
+optgroup {
+    font-weight: bolder;
+    display: block;
+}
+
+option {
+    font-weight: normal;
+    display: block;
+    padding: 0 2px 1px 2px;
+    white-space: pre;
+    min-height: 1.2em;
+}
+
+output {
+    display: inline;
+}
+
+/* meter */
+
+meter {
+    -webkit-appearance: meter;
+    box-sizing: border-box;
+    display: inline-block;
+    height: 1em;
+    width: 5em;
+    vertical-align: -0.2em;
+}
+
+/* progress */
+
+progress {
+    -webkit-appearance: progress-bar;
+    box-sizing: border-box;
+    display: inline-block;
+    height: 1em;
+    width: 10em;
+    vertical-align: -0.2em;
+}
+
+/* inline elements */
+
+u, ins {
+    text-decoration: underline
+}
+
+strong, b {
+    font-weight: bold
+}
+
+i, cite, em, var, address, dfn {
+    font-style: italic
+}
+
+tt, code, kbd, samp {
+    font-family: monospace
+}
+
+pre, xmp, plaintext, listing {
+    display: block;
+    font-family: monospace;
+    white-space: pre;
+    margin: 1__qem 0
+}
+
+mark {
+    background-color: yellow;
+    color: black
+}
+
+big {
+    font-size: larger
+}
+
+small {
+    font-size: smaller
+}
+
+s, strike, del {
+    text-decoration: line-through
+}
+
+sub {
+    vertical-align: sub;
+    font-size: smaller
+}
+
+sup {
+    vertical-align: super;
+    font-size: smaller
+}
+
+nobr {
+    white-space: nowrap
+}
+
+/* states */
+
+:focus {
+    outline: auto 5px -webkit-focus-ring-color
+}
+
+/* Read-only text fields do not show a focus ring but do still receive focus */
+html:focus, body:focus, input[readonly]:focus {
+    outline: none
+}
+
+embed:focus, iframe:focus, object:focus {
+    outline: none
+}
+
+input:focus, textarea:focus, select:focus {
+    outline-offset: -2px
+}
+
+input[type="button"]:focus,
+input[type="checkbox"]:focus,
+input[type="file"]:focus,
+input[type="hidden"]:focus,
+input[type="image"]:focus,
+input[type="radio"]:focus,
+input[type="reset"]:focus,
+input[type="search"]:focus,
+input[type="submit"]:focus {
+    outline-offset: 0
+}
+
+/* HTML5 ruby elements */
+
+ruby, rt {
+    text-indent: 0; /* blocks used for ruby rendering should not trigger this */
+}
+
+rt {
+    line-height: normal;
+    -webkit-text-emphasis: none;
+}
+
+ruby > rt {
+    display: block;
+    font-size: 50%;
+    text-align: start;
+}
+
+ruby > rp {
+    display: none;
+}
+
+/* other elements */
+
+noframes {
+    display: none
+}
+
+frameset, frame {
+    display: block
+}
+
+frameset {
+    border-color: inherit
+}
+
+iframe {
+    border: 2px inset
+}
+
+details {
+    display: block
+}
+
+summary {
+    display: block
+}
+
+template {
+    display: none
+}
+
+bdi, output {
+    unicode-bidi: -webkit-isolate;
+}
+
+bdo {
+    unicode-bidi: bidi-override;
+}
+
+textarea[dir=auto] {
+    unicode-bidi: -webkit-plaintext;
+}
+
+dialog:not([open]) {
+    display: none
+}
+
+dialog {
+    position: absolute;
+    left: 0;
+    right: 0;
+    width: -webkit-fit-content;
+    height: -webkit-fit-content;
+    margin: auto;
+    border: solid;
+    padding: 1em;
+    background: white;
+    color: black
+}
+
+[hidden] {
+    display: none
+}
+
+/* noscript is handled internally, as it depends on settings. */
+
+`;
Index: frontend/node_modules/jsdom/lib/jsdom/browser/js-globals.json
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/js-globals.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/js-globals.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,307 @@
+{
+  "Object": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Function": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Number": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "parseFloat": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "parseInt": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Infinity": {
+    "writable": false,
+    "enumerable": false,
+    "configurable": false
+  },
+  "NaN": {
+    "writable": false,
+    "enumerable": false,
+    "configurable": false
+  },
+  "undefined": {
+    "writable": false,
+    "enumerable": false,
+    "configurable": false
+  },
+  "Boolean": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "String": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Symbol": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Date": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Promise": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "RegExp": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Error": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "AggregateError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "EvalError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "RangeError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "ReferenceError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "SyntaxError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "TypeError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "URIError": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "globalThis": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "JSON": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Math": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Intl": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "ArrayBuffer": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Uint8Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Int8Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Uint16Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Int16Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Uint32Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Int32Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Float32Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Float64Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Uint8ClampedArray": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "BigUint64Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "BigInt64Array": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "DataView": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Map": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "BigInt": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Set": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "WeakMap": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "WeakSet": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Proxy": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Reflect": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "FinalizationRegistry": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "WeakRef": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "decodeURI": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "decodeURIComponent": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "encodeURI": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "encodeURIComponent": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "escape": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "unescape": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "eval": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "isFinite": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "isNaN": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "SharedArrayBuffer": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "Atomics": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  },
+  "WebAssembly": {
+    "writable": true,
+    "enumerable": false,
+    "configurable": true
+  }
+}
Index: frontend/node_modules/jsdom/lib/jsdom/browser/not-implemented.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/not-implemented.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/not-implemented.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+module.exports = function (nameForErrorMessage, window) {
+  if (!window) {
+    // Do nothing for window-less documents.
+    return;
+  }
+
+  const error = new Error(`Not implemented: ${nameForErrorMessage}`);
+  error.type = "not implemented";
+
+  window._virtualConsole.emit("jsdomError", error);
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/parser/html.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/parser/html.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/parser/html.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,223 @@
+"use strict";
+
+const parse5 = require("parse5");
+
+const { createElement } = require("../../living/helpers/create-element");
+const { HTML_NS } = require("../../living/helpers/namespaces");
+
+const DocumentType = require("../../living/generated/DocumentType");
+const DocumentFragment = require("../../living/generated/DocumentFragment");
+const Text = require("../../living/generated/Text");
+const Comment = require("../../living/generated/Comment");
+
+const attributes = require("../../living/attributes");
+const nodeTypes = require("../../living/node-type");
+
+const serializationAdapter = require("../../living/domparsing/parse5-adapter-serialization");
+const {
+  customElementReactionsStack, invokeCEReactions, lookupCEDefinition
+} = require("../../living/helpers/custom-elements");
+
+// Horrible monkey-patch to implement https://github.com/inikulin/parse5/issues/237 and
+// https://github.com/inikulin/parse5/issues/285.
+const OpenElementStack = require("parse5/lib/parser/open-element-stack");
+
+const openElementStackOriginalPush = OpenElementStack.prototype.push;
+OpenElementStack.prototype.push = function (...args) {
+  openElementStackOriginalPush.apply(this, args);
+  this.treeAdapter._currentElement = this.current;
+
+  const after = this.items[this.stackTop];
+  if (after._pushedOnStackOfOpenElements) {
+    after._pushedOnStackOfOpenElements();
+  }
+};
+
+const openElementStackOriginalPop = OpenElementStack.prototype.pop;
+OpenElementStack.prototype.pop = function (...args) {
+  const before = this.items[this.stackTop];
+
+  openElementStackOriginalPop.apply(this, args);
+  this.treeAdapter._currentElement = this.current;
+
+  if (before._poppedOffStackOfOpenElements) {
+    before._poppedOffStackOfOpenElements();
+  }
+};
+
+class JSDOMParse5Adapter {
+  constructor(documentImpl, options = {}) {
+    this._documentImpl = documentImpl;
+    this._globalObject = documentImpl._globalObject;
+    this._fragment = options.fragment || false;
+
+    // Since the createElement hook doesn't provide the parent element, we keep track of this using _currentElement:
+    // https://github.com/inikulin/parse5/issues/285. See above horrible monkey-patch for how this is maintained.
+    this._currentElement = undefined;
+  }
+
+  _ownerDocument() {
+    const { _currentElement } = this;
+
+    // The _currentElement is undefined when parsing elements at the root of the document.
+    if (_currentElement) {
+      return _currentElement.localName === "template" && _currentElement.namespaceURI === HTML_NS ?
+        _currentElement.content._ownerDocument :
+        _currentElement._ownerDocument;
+    }
+
+    return this._documentImpl;
+  }
+
+  createDocument() {
+    // parse5's model assumes that parse(html) will call into here to create the new Document, then return it. However,
+    // jsdom's model assumes we can create a Window (and through that create an empty Document), do some other setup
+    // stuff, and then parse, stuffing nodes into that Document as we go. So to adapt between these two models, we just
+    // return the already-created Document when asked by parse5 to "create" a Document.
+    return this._documentImpl;
+  }
+
+  createDocumentFragment() {
+    const ownerDocument = this._ownerDocument();
+    return DocumentFragment.createImpl(this._globalObject, [], { ownerDocument });
+  }
+
+  // https://html.spec.whatwg.org/#create-an-element-for-the-token
+  createElement(localName, namespace, attrs) {
+    const ownerDocument = this._ownerDocument();
+
+    const isAttribute = attrs.find(attr => attr.name === "is");
+    const isValue = isAttribute ? isAttribute.value : null;
+
+    const definition = lookupCEDefinition(ownerDocument, namespace, localName);
+
+    let willExecuteScript = false;
+    if (definition !== null && !this._fragment) {
+      willExecuteScript = true;
+    }
+
+    if (willExecuteScript) {
+      ownerDocument._throwOnDynamicMarkupInsertionCounter++;
+      customElementReactionsStack.push([]);
+    }
+
+    const element = createElement(ownerDocument, localName, namespace, null, isValue, willExecuteScript);
+    this.adoptAttributes(element, attrs);
+
+    if (willExecuteScript) {
+      const queue = customElementReactionsStack.pop();
+      invokeCEReactions(queue);
+      ownerDocument._throwOnDynamicMarkupInsertionCounter--;
+    }
+
+    if ("_parserInserted" in element) {
+      element._parserInserted = true;
+    }
+
+    return element;
+  }
+
+  createCommentNode(data) {
+    const ownerDocument = this._ownerDocument();
+    return Comment.createImpl(this._globalObject, [], { data, ownerDocument });
+  }
+
+  appendChild(parentNode, newNode) {
+    parentNode._append(newNode);
+  }
+
+  insertBefore(parentNode, newNode, referenceNode) {
+    parentNode._insert(newNode, referenceNode);
+  }
+
+  setTemplateContent(templateElement, contentFragment) {
+    // This code makes the glue between jsdom and parse5 HTMLTemplateElement parsing:
+    //
+    // * jsdom during the construction of the HTMLTemplateElement (for example when create via
+    //   `document.createElement("template")`), creates a DocumentFragment and set it into _templateContents.
+    // * parse5 when parsing a <template> tag creates an HTMLTemplateElement (`createElement` adapter hook) and also
+    //   create a DocumentFragment (`createDocumentFragment` adapter hook).
+    //
+    // At this point we now have to replace the one created in jsdom with one created by parse5.
+    const { _ownerDocument, _host } = templateElement._templateContents;
+    contentFragment._ownerDocument = _ownerDocument;
+    contentFragment._host = _host;
+
+    templateElement._templateContents = contentFragment;
+  }
+
+  setDocumentType(document, name, publicId, systemId) {
+    const ownerDocument = this._ownerDocument();
+    const documentType = DocumentType.createImpl(this._globalObject, [], { name, publicId, systemId, ownerDocument });
+
+    document._append(documentType);
+  }
+
+  setDocumentMode(document, mode) {
+    // TODO: the rest of jsdom ignores this
+    document._mode = mode;
+  }
+
+  detachNode(node) {
+    node.remove();
+  }
+
+  insertText(parentNode, text) {
+    const { lastChild } = parentNode;
+    if (lastChild && lastChild.nodeType === nodeTypes.TEXT_NODE) {
+      lastChild.data += text;
+    } else {
+      const ownerDocument = this._ownerDocument();
+      const textNode = Text.createImpl(this._globalObject, [], { data: text, ownerDocument });
+      parentNode._append(textNode);
+    }
+  }
+
+  insertTextBefore(parentNode, text, referenceNode) {
+    const { previousSibling } = referenceNode;
+    if (previousSibling && previousSibling.nodeType === nodeTypes.TEXT_NODE) {
+      previousSibling.data += text;
+    } else {
+      const ownerDocument = this._ownerDocument();
+      const textNode = Text.createImpl(this._globalObject, [], { data: text, ownerDocument });
+      parentNode._append(textNode, referenceNode);
+    }
+  }
+
+  adoptAttributes(element, attrs) {
+    for (const attr of attrs) {
+      const prefix = attr.prefix === "" ? null : attr.prefix;
+      attributes.setAttributeValue(element, attr.name, attr.value, prefix, attr.namespace);
+    }
+  }
+}
+
+// Assign shared adapters with serializer.
+Object.assign(JSDOMParse5Adapter.prototype, serializationAdapter);
+
+function parseFragment(markup, contextElement) {
+  const ownerDocument = contextElement.localName === "template" && contextElement.namespaceURI === HTML_NS ?
+    contextElement.content._ownerDocument :
+    contextElement._ownerDocument;
+
+  const config = {
+    ...ownerDocument._parseOptions,
+    treeAdapter: new JSDOMParse5Adapter(ownerDocument, { fragment: true })
+  };
+
+  return parse5.parseFragment(contextElement, markup, config);
+}
+
+function parseIntoDocument(markup, ownerDocument) {
+  const config = {
+    ...ownerDocument._parseOptions,
+    treeAdapter: new JSDOMParse5Adapter(ownerDocument)
+  };
+
+  return parse5.parse(markup, config);
+}
+
+module.exports = {
+  parseFragment,
+  parseIntoDocument
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/parser/index.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/parser/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/parser/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+"use strict";
+
+const xmlParser = require("./xml");
+const htmlParser = require("./html");
+
+// https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm
+function parseFragment(markup, contextElement) {
+  const { _parsingMode } = contextElement._ownerDocument;
+
+  let parseAlgorithm;
+  if (_parsingMode === "html") {
+    parseAlgorithm = htmlParser.parseFragment;
+  } else if (_parsingMode === "xml") {
+    parseAlgorithm = xmlParser.parseFragment;
+  }
+
+  // Note: HTML and XML fragment parsing algorithm already return a document fragments; no need to do steps 3 and 4
+  return parseAlgorithm(markup, contextElement);
+}
+
+function parseIntoDocument(markup, ownerDocument) {
+  const { _parsingMode } = ownerDocument;
+
+  let parseAlgorithm;
+  if (_parsingMode === "html") {
+    parseAlgorithm = htmlParser.parseIntoDocument;
+  } else if (_parsingMode === "xml") {
+    parseAlgorithm = xmlParser.parseIntoDocument;
+  }
+
+  return parseAlgorithm(markup, ownerDocument);
+}
+
+module.exports = {
+  parseFragment,
+  parseIntoDocument
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/parser/xml.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/parser/xml.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/parser/xml.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,202 @@
+"use strict";
+
+const { SaxesParser } = require("saxes");
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const { createElement } = require("../../living/helpers/create-element");
+
+const DocumentFragment = require("../../living/generated/DocumentFragment");
+const DocumentType = require("../../living/generated/DocumentType");
+const CDATASection = require("../../living/generated/CDATASection");
+const Comment = require("../../living/generated/Comment");
+const ProcessingInstruction = require("../../living/generated/ProcessingInstruction");
+const Text = require("../../living/generated/Text");
+
+const attributes = require("../../living/attributes");
+const { HTML_NS } = require("../../living/helpers/namespaces");
+
+const HTML5_DOCTYPE = /<!doctype html>/i;
+const PUBLIC_DOCTYPE = /<!doctype\s+([^\s]+)\s+public\s+"([^"]+)"\s+"([^"]+)"/i;
+const SYSTEM_DOCTYPE = /<!doctype\s+([^\s]+)\s+system\s+"([^"]+)"/i;
+const CUSTOM_NAME_DOCTYPE = /<!doctype\s+([^\s>]+)/i;
+
+function parseDocType(globalObject, ownerDocument, html) {
+  if (HTML5_DOCTYPE.test(html)) {
+    return createDocumentType(globalObject, ownerDocument, "html", "", "");
+  }
+
+  const publicPieces = PUBLIC_DOCTYPE.exec(html);
+  if (publicPieces) {
+    return createDocumentType(globalObject, ownerDocument, publicPieces[1], publicPieces[2], publicPieces[3]);
+  }
+
+  const systemPieces = SYSTEM_DOCTYPE.exec(html);
+  if (systemPieces) {
+    return createDocumentType(globalObject, ownerDocument, systemPieces[1], "", systemPieces[2]);
+  }
+
+  const namePiece = CUSTOM_NAME_DOCTYPE.exec(html)[1] || "html";
+  return createDocumentType(globalObject, ownerDocument, namePiece, "", "");
+}
+
+function createDocumentType(globalObject, ownerDocument, name, publicId, systemId) {
+  return DocumentType.createImpl(globalObject, [], { ownerDocument, name, publicId, systemId });
+}
+
+function isHTMLTemplateElement(element) {
+  return element.tagName === "template" && element.namespaceURI === HTML_NS;
+}
+
+
+function createParser(rootNode, globalObject, saxesOptions) {
+  const parser = new SaxesParser({
+    ...saxesOptions,
+    // Browsers always have namespace support.
+    xmlns: true,
+    // We force the parser to treat all documents (even documents declaring themselves to be XML 1.1 documents) as XML
+    // 1.0 documents. See https://github.com/jsdom/jsdom/issues/2677 for a discussion of the stakes.
+    defaultXMLVersion: "1.0",
+    forceXMLVersion: true
+  });
+  const openStack = [rootNode];
+
+  function getOwnerDocument() {
+    const currentElement = openStack[openStack.length - 1];
+
+    return isHTMLTemplateElement(currentElement) ?
+      currentElement._templateContents._ownerDocument :
+      currentElement._ownerDocument;
+  }
+
+  function appendChild(child) {
+    const parentElement = openStack[openStack.length - 1];
+
+    if (isHTMLTemplateElement(parentElement)) {
+      parentElement._templateContents._insert(child, null);
+    } else {
+      parentElement._insert(child, null);
+    }
+  }
+
+  parser.on("text", saxesOptions.fragment ?
+    // In a fragment, all text events produced by saxes must result in a text
+    // node.
+    data => {
+      const ownerDocument = getOwnerDocument();
+      appendChild(Text.createImpl(globalObject, [], { data, ownerDocument }));
+    } :
+    // When parsing a whole document, we must ignore those text nodes that are
+    // produced outside the root element. Saxes produces events for them,
+    // but DOM trees do not record text outside the root element.
+    data => {
+      if (openStack.length > 1) {
+        const ownerDocument = getOwnerDocument();
+        appendChild(Text.createImpl(globalObject, [], { data, ownerDocument }));
+      }
+    });
+
+  parser.on("cdata", data => {
+    const ownerDocument = getOwnerDocument();
+    appendChild(CDATASection.createImpl(globalObject, [], { data, ownerDocument }));
+  });
+
+  parser.on("opentag", tag => {
+    const { local: tagLocal, attributes: tagAttributes } = tag;
+
+    const ownerDocument = getOwnerDocument();
+    const tagNamespace = tag.uri === "" ? null : tag.uri;
+    const tagPrefix = tag.prefix === "" ? null : tag.prefix;
+    const isValue = tagAttributes.is === undefined ? null : tagAttributes.is.value;
+
+    const elem = createElement(ownerDocument, tagLocal, tagNamespace, tagPrefix, isValue, true);
+
+    // We mark a script element as "parser-inserted", which prevents it from
+    // being immediately executed.
+    if (tagLocal === "script" && tagNamespace === HTML_NS) {
+      elem._parserInserted = true;
+    }
+
+    for (const key of Object.keys(tagAttributes)) {
+      const { prefix, local, uri, value } = tagAttributes[key];
+      attributes.setAttributeValue(elem, local, value, prefix === "" ? null : prefix, uri === "" ? null : uri);
+    }
+
+    appendChild(elem);
+    openStack.push(elem);
+  });
+
+  parser.on("closetag", () => {
+    const elem = openStack.pop();
+    // Once a script is populated, we can execute it.
+    if (elem.localName === "script" && elem.namespaceURI === HTML_NS) {
+      elem._eval();
+    }
+  });
+
+  parser.on("comment", data => {
+    const ownerDocument = getOwnerDocument();
+    appendChild(Comment.createImpl(globalObject, [], { data, ownerDocument }));
+  });
+
+  parser.on("processinginstruction", ({ target, body }) => {
+    const ownerDocument = getOwnerDocument();
+    appendChild(ProcessingInstruction.createImpl(globalObject, [], { target, data: body, ownerDocument }));
+  });
+
+  parser.on("doctype", dt => {
+    const ownerDocument = getOwnerDocument();
+    appendChild(parseDocType(globalObject, ownerDocument, `<!doctype ${dt}>`));
+
+    const entityMatcher = /<!ENTITY ([^ ]+) "([^"]+)">/g;
+    let result;
+    while ((result = entityMatcher.exec(dt))) {
+      const [, name, value] = result;
+      if (!(name in parser.ENTITIES)) {
+        parser.ENTITIES[name] = value;
+      }
+    }
+  });
+
+  parser.on("error", err => {
+    throw DOMException.create(globalObject, [err.message, "SyntaxError"]);
+  });
+
+  return parser;
+}
+
+function parseFragment(markup, contextElement) {
+  const { _globalObject, _ownerDocument } = contextElement;
+
+  const fragment = DocumentFragment.createImpl(_globalObject, [], { ownerDocument: _ownerDocument });
+
+  // Only parseFragment needs resolvePrefix per the saxes documentation:
+  // https://github.com/lddubeau/saxes#parsing-xml-fragments
+  const parser = createParser(fragment, _globalObject, {
+    fragment: true,
+    resolvePrefix(prefix) {
+      // saxes wants undefined as the return value if the prefix is not defined, not null.
+      return contextElement.lookupNamespaceURI(prefix) || undefined;
+    }
+  });
+
+  parser.write(markup).close();
+
+  return fragment;
+}
+
+function parseIntoDocument(markup, ownerDocument) {
+  const { _globalObject } = ownerDocument;
+
+  const parser = createParser(ownerDocument, _globalObject, {
+    fileName: ownerDocument.location && ownerDocument.location.href
+  });
+
+  parser.write(markup).close();
+
+  return ownerDocument;
+}
+
+module.exports = {
+  parseFragment,
+  parseIntoDocument
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+class QueueItem {
+  constructor(onLoad, onError, dependentItem) {
+    this.onLoad = onLoad;
+    this.onError = onError;
+    this.data = null;
+    this.error = null;
+    this.dependentItem = dependentItem;
+  }
+}
+
+/**
+ * AsyncResourceQueue is the queue in charge of run the async scripts
+ * and notify when they finish.
+ */
+module.exports = class AsyncResourceQueue {
+  constructor() {
+    this.items = new Set();
+    this.dependentItems = new Set();
+  }
+
+  count() {
+    return this.items.size + this.dependentItems.size;
+  }
+
+  _notify() {
+    if (this._listener) {
+      this._listener();
+    }
+  }
+
+  _check(item) {
+    let promise;
+
+    if (item.onError && item.error) {
+      promise = item.onError(item.error);
+    } else if (item.onLoad && item.data) {
+      promise = item.onLoad(item.data);
+    }
+
+    promise
+      .then(() => {
+        this.items.delete(item);
+        this.dependentItems.delete(item);
+
+        if (this.count() === 0) {
+          this._notify();
+        }
+      });
+  }
+
+  setListener(listener) {
+    this._listener = listener;
+  }
+
+  push(request, onLoad, onError, dependentItem) {
+    const q = this;
+
+    const item = new QueueItem(onLoad, onError, dependentItem);
+
+    q.items.add(item);
+
+    return request
+      .then(data => {
+        item.data = data;
+
+        if (dependentItem && !dependentItem.finished) {
+          q.dependentItems.add(item);
+          return q.items.delete(item);
+        }
+
+        if (onLoad) {
+          return q._check(item);
+        }
+
+        q.items.delete(item);
+
+        if (q.count() === 0) {
+          q._notify();
+        }
+
+        return null;
+      })
+      .catch(err => {
+        item.error = err;
+
+        if (dependentItem && !dependentItem.finished) {
+          q.dependentItems.add(item);
+          return q.items.delete(item);
+        }
+
+        if (onError) {
+          return q._check(item);
+        }
+
+        q.items.delete(item);
+
+        if (q.count() === 0) {
+          q._notify();
+        }
+
+        return null;
+      });
+  }
+
+  notifyItem(syncItem) {
+    for (const item of this.dependentItems) {
+      if (item.dependentItem === syncItem) {
+        this._check(item);
+      }
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+"use strict";
+const ResourceLoader = require("./resource-loader.js");
+
+module.exports = class NoOpResourceLoader extends ResourceLoader {
+  fetch() {
+    return null;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+"use strict";
+const idlUtils = require("../../living/generated/utils");
+const { fireAnEvent } = require("../../living/helpers/events");
+
+module.exports = class PerDocumentResourceLoader {
+  constructor(document) {
+    this._document = document;
+    this._defaultEncoding = document._encoding;
+    this._resourceLoader = document._defaultView ? document._defaultView._resourceLoader : null;
+    this._requestManager = document._requestManager;
+    this._queue = document._queue;
+    this._deferQueue = document._deferQueue;
+    this._asyncQueue = document._asyncQueue;
+  }
+
+  fetch(url, { element, onLoad, onError }) {
+    const request = this._resourceLoader.fetch(url, {
+      cookieJar: this._document._cookieJar,
+      element: idlUtils.wrapperForImpl(element),
+      referrer: this._document.URL
+    });
+
+    if (request === null) {
+      return null;
+    }
+
+    this._requestManager.add(request);
+
+    const onErrorWrapped = error => {
+      this._requestManager.remove(request);
+
+      if (onError) {
+        onError(error);
+      }
+
+      fireAnEvent("error", element);
+
+      const err = new Error(`Could not load ${element.localName}: "${url}"`);
+      err.type = "resource loading";
+      err.detail = error;
+
+      this._document._defaultView._virtualConsole.emit("jsdomError", err);
+
+      return Promise.resolve();
+    };
+
+    const onLoadWrapped = data => {
+      this._requestManager.remove(request);
+
+      this._addCookies(url, request.response ? request.response.headers : {});
+
+      try {
+        const result = onLoad ? onLoad(data) : undefined;
+
+        return Promise.resolve(result)
+          .then(() => {
+            fireAnEvent("load", element);
+
+            return Promise.resolve();
+          })
+          .catch(err => {
+            return onErrorWrapped(err);
+          });
+      } catch (err) {
+        return onErrorWrapped(err);
+      }
+    };
+
+    if (element.localName === "script" && element.hasAttributeNS(null, "async")) {
+      this._asyncQueue.push(request, onLoadWrapped, onErrorWrapped, this._queue.getLastScript());
+    } else if (element.localName === "script" && element.hasAttributeNS(null, "defer")) {
+      this._deferQueue.push(request, onLoadWrapped, onErrorWrapped, false, element);
+    } else {
+      this._queue.push(request, onLoadWrapped, onErrorWrapped, false, element);
+    }
+
+    return request;
+  }
+
+  _addCookies(url, headers) {
+    let cookies = headers["set-cookie"];
+
+    if (!cookies) {
+      return;
+    }
+
+    if (!Array.isArray(cookies)) {
+      cookies = [cookies];
+    }
+
+    cookies.forEach(cookie => {
+      this._document._cookieJar.setCookieSync(cookie, url, { http: true, ignoreError: true });
+    });
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,33 @@
+"use strict";
+
+/**
+ * Manage all the request and it is able to abort
+ * all pending request.
+ */
+module.exports = class RequestManager {
+  constructor() {
+    this.openedRequests = [];
+  }
+
+  add(req) {
+    this.openedRequests.push(req);
+  }
+
+  remove(req) {
+    const idx = this.openedRequests.indexOf(req);
+    if (idx !== -1) {
+      this.openedRequests.splice(idx, 1);
+    }
+  }
+
+  close() {
+    for (const openedRequest of this.openedRequests) {
+      openedRequest.abort();
+    }
+    this.openedRequests = [];
+  }
+
+  size() {
+    return this.openedRequests.length;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,142 @@
+"use strict";
+const fs = require("fs");
+const { fileURLToPath } = require("url");
+const { parseURL } = require("whatwg-url");
+const dataURLFromRecord = require("data-urls").fromURLRecord;
+const packageVersion = require("../../../../package.json").version;
+const agentFactory = require("../../living/helpers/agent-factory");
+const Request = require("../../living/helpers/http-request");
+
+const IS_BROWSER = Object.prototype.toString.call(process) !== "[object process]";
+
+module.exports = class ResourceLoader {
+  constructor({
+    strictSSL = true,
+    proxy = undefined,
+    userAgent = `Mozilla/5.0 (${process.platform || "unknown OS"}) AppleWebKit/537.36 ` +
+                `(KHTML, like Gecko) jsdom/${packageVersion}`
+  } = {}) {
+    this._strictSSL = strictSSL;
+    this._proxy = proxy;
+    this._userAgent = userAgent;
+  }
+
+  _readDataURL(urlRecord) {
+    const dataURL = dataURLFromRecord(urlRecord);
+    let timeoutId;
+    const promise = new Promise(resolve => {
+      timeoutId = setTimeout(resolve, 0, dataURL.body);
+    });
+    promise.abort = () => {
+      if (timeoutId !== undefined) {
+        clearTimeout(timeoutId);
+      }
+    };
+    return promise;
+  }
+
+  _readFile(filePath) {
+    let readableStream, abort; // Native Promises doesn't have an "abort" method.
+
+    // Creating a promise for two reason:
+    //   1. fetch always return a promise.
+    //   2. We need to add an abort handler.
+    const promise = new Promise((resolve, reject) => {
+      readableStream = fs.createReadStream(filePath);
+      let data = Buffer.alloc(0);
+
+      abort = reject;
+
+      readableStream.on("error", reject);
+
+      readableStream.on("data", chunk => {
+        data = Buffer.concat([data, chunk]);
+      });
+
+      readableStream.on("end", () => {
+        resolve(data);
+      });
+    });
+
+    promise.abort = () => {
+      readableStream.destroy();
+      const error = new Error("request canceled by user");
+      error.isAbortError = true;
+      abort(error);
+    };
+
+    return promise;
+  }
+
+  fetch(urlString, { accept, cookieJar, referrer } = {}) {
+    const url = parseURL(urlString);
+
+    if (!url) {
+      return Promise.reject(new Error(`Tried to fetch invalid URL ${urlString}`));
+    }
+
+    switch (url.scheme) {
+      case "data": {
+        return this._readDataURL(url);
+      }
+
+      case "http":
+      case "https": {
+        const agents = agentFactory(this._proxy, this._strictSSL);
+        const headers = {
+          "User-Agent": this._userAgent,
+          "Accept-Language": "en",
+          "Accept-Encoding": "gzip",
+          "Accept": accept || "*/*"
+        };
+        if (referrer && !IS_BROWSER) {
+          headers.Referer = referrer;
+        }
+        const requestClient = new Request(
+          urlString,
+          { followRedirects: true, cookieJar, agents },
+          { headers }
+        );
+        const promise = new Promise((resolve, reject) => {
+          const accumulated = [];
+          requestClient.once("response", res => {
+            promise.response = res;
+            const { statusCode } = res;
+            // TODO This deviates from the spec when it comes to
+            // loading resources such as images
+            if (statusCode < 200 || statusCode > 299) {
+              requestClient.abort();
+              reject(new Error(`Resource was not loaded. Status: ${statusCode}`));
+            }
+          });
+          requestClient.on("data", chunk => {
+            accumulated.push(chunk);
+          });
+          requestClient.on("end", () => resolve(Buffer.concat(accumulated)));
+          requestClient.on("error", reject);
+        });
+        // The method fromURL in lib/api.js crashes without the following four
+        // properties defined on the Promise instance, causing the test suite to halt
+        requestClient.on("end", () => {
+          promise.href = requestClient.currentURL;
+        });
+        promise.abort = requestClient.abort.bind(requestClient);
+        promise.getHeader = name => headers[name] || requestClient.getHeader(name);
+        requestClient.end();
+        return promise;
+      }
+
+      case "file": {
+        try {
+          return this._readFile(fileURLToPath(urlString));
+        } catch (e) {
+          return Promise.reject(e);
+        }
+      }
+
+      default: {
+        return Promise.reject(new Error(`Tried to fetch URL ${urlString} with invalid scheme ${url.scheme}`));
+      }
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,142 @@
+"use strict";
+
+/**
+ * Queue for all the resources to be download except async scripts.
+ * Async scripts have their own queue AsyncResourceQueue.
+ */
+module.exports = class ResourceQueue {
+  constructor({ paused, asyncQueue } = {}) {
+    this.paused = Boolean(paused);
+    this._asyncQueue = asyncQueue;
+  }
+
+  getLastScript() {
+    let head = this.tail;
+
+    while (head) {
+      if (head.isScript) {
+        return head;
+      }
+      head = head.prev;
+    }
+
+    return null;
+  }
+
+  _moreScripts() {
+    let found = false;
+
+    let head = this.tail;
+    while (head && !found) {
+      found = head.isScript;
+      head = head.prev;
+    }
+
+    return found;
+  }
+
+  _notify() {
+    if (this._listener) {
+      this._listener();
+    }
+  }
+
+  setListener(listener) {
+    this._listener = listener;
+  }
+
+  push(request, onLoad, onError, keepLast, element) {
+    const isScript = element ? element.localName === "script" : false;
+
+    if (!request) {
+      if (isScript && !this._moreScripts()) {
+        return onLoad();
+      }
+
+      request = Promise.resolve();
+    }
+    const q = this;
+    const item = {
+      isScript,
+      err: null,
+      element,
+      fired: false,
+      data: null,
+      keepLast,
+      prev: q.tail,
+      check() {
+        if (!q.paused && !this.prev && this.fired) {
+          let promise;
+
+          if (this.err && onError) {
+            promise = onError(this.err);
+          }
+
+          if (!this.err && onLoad) {
+            promise = onLoad(this.data);
+          }
+
+          Promise.resolve(promise)
+            .then(() => {
+              if (this.next) {
+                this.next.prev = null;
+                this.next.check();
+              } else { // q.tail===this
+                q.tail = null;
+                q._notify();
+              }
+
+              this.finished = true;
+
+              if (q._asyncQueue) {
+                q._asyncQueue.notifyItem(this);
+              }
+            });
+        }
+      }
+    };
+    if (q.tail) {
+      if (q.tail.keepLast) {
+        // if the tail is the load event in document and we receive a new element to load
+        // we should add this new request before the load event.
+        if (q.tail.prev) {
+          q.tail.prev.next = item;
+        }
+        item.prev = q.tail.prev;
+        q.tail.prev = item;
+        item.next = q.tail;
+      } else {
+        q.tail.next = item;
+        q.tail = item;
+      }
+    } else {
+      q.tail = item;
+    }
+    return request
+      .then(data => {
+        item.fired = 1;
+        item.data = data;
+        item.check();
+      })
+      .catch(err => {
+        item.fired = true;
+        item.err = err;
+        item.check();
+      });
+  }
+
+  resume() {
+    if (!this.paused) {
+      return;
+    }
+    this.paused = false;
+
+    let head = this.tail;
+    while (head && head.prev) {
+      head = head.prev;
+    }
+    if (head) {
+      head.check();
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/level2/style.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/level2/style.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/level2/style.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,57 @@
+"use strict";
+const cssom = require("cssom");
+const cssstyle = require("cssstyle");
+
+exports.addToCore = core => {
+  // What works now:
+  // - Accessing the rules defined in individual stylesheets
+  // - Modifications to style content attribute are reflected in style property
+  // - Modifications to style property are reflected in style content attribute
+  // TODO
+  // - Modifications to style element's textContent are reflected in sheet property.
+  // - Modifications to style element's sheet property are reflected in textContent.
+  // - Modifications to link.href property are reflected in sheet property.
+  // - Less-used features of link: disabled
+  // - Less-used features of style: disabled, scoped, title
+  // - CSSOM-View
+  //   - getComputedStyle(): requires default stylesheet, cascading, inheritance,
+  //     filtering by @media (screen? print?), layout for widths/heights
+  // - Load events are not in the specs, but apparently some browsers
+  //   implement something. Should onload only fire after all @imports have been
+  //   loaded, or only the primary sheet?
+
+  core.StyleSheet = cssom.StyleSheet;
+  core.MediaList = cssom.MediaList;
+  core.CSSStyleSheet = cssom.CSSStyleSheet;
+  core.CSSRule = cssom.CSSRule;
+  core.CSSStyleRule = cssom.CSSStyleRule;
+  core.CSSMediaRule = cssom.CSSMediaRule;
+  core.CSSImportRule = cssom.CSSImportRule;
+  core.CSSStyleDeclaration = cssstyle.CSSStyleDeclaration;
+
+  // Relavant specs
+  // http://www.w3.org/TR/DOM-Level-2-Style (2000)
+  // http://www.w3.org/TR/cssom-view/ (2008)
+  // http://dev.w3.org/csswg/cssom/ (2010) Meant to replace DOM Level 2 Style
+  // http://www.whatwg.org/specs/web-apps/current-work/multipage/ HTML5, of course
+  // http://dev.w3.org/csswg/css-style-attr/  not sure what's new here
+
+  // Objects that aren't in cssom library but should be:
+  //   CSSRuleList  (cssom just uses array)
+  //   CSSFontFaceRule
+  //   CSSPageRule
+
+  // These rules don't really make sense to implement, so CSSOM draft makes them
+  // obsolete.
+  //   CSSCharsetRule
+  //   CSSUnknownRule
+
+  // These objects are considered obsolete by CSSOM draft, although modern
+  // browsers implement them.
+  //   CSSValue
+  //   CSSPrimitiveValue
+  //   CSSValueList
+  //   RGBColor
+  //   Rect
+  //   Counter
+};
Index: frontend/node_modules/jsdom/lib/jsdom/level3/xpath.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/level3/xpath.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/level3/xpath.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1874 @@
+/** Here is yet another implementation of XPath 1.0 in Javascript.
+ *
+ * My goal was to make it relatively compact, but as I fixed all the axis bugs
+ * the axes became more and more complicated. :-(.
+ *
+ * I have not implemented namespaces or case-sensitive axes for XML yet.
+ *
+ * How to test it in Chrome: You can make a Chrome extension that replaces
+ * the WebKit XPath parser with this one. But it takes a bit of effort to
+ * get around isolated world and same-origin restrictions:
+ * manifest.json:
+    {
+      "name": "XPathTest",
+      "version": "0.1",
+      "content_scripts": [{
+        "matches": ["http://localhost/*"],  // or wildcard host
+        "js": ["xpath.js", "injection.js"],
+        "all_frames": true, "run_at": "document_start"
+      }]
+    }
+ * injection.js:
+    // goal: give my xpath object to the website's JS context.
+    var script = document.createElement('script');
+    script.textContent =
+        "document.addEventListener('xpathextend', function(e) {\n" +
+        "  console.log('extending document with xpath...');\n" +
+        "  e.detail(window);" +
+        "});";
+    document.documentElement.appendChild(script);
+    document.documentElement.removeChild(script);
+    var evt = document.createEvent('CustomEvent');
+    evt.initCustomEvent('xpathextend', true, true, this.xpath.extend);
+    document.dispatchEvent(evt);
+ */
+module.exports = core => {
+  var xpath = {};
+
+  // Helper function to deal with the migration of Attr to no longer have a nodeName property despite this codebase
+  // assuming it does.
+  function getNodeName(nodeOrAttr) {
+    return nodeOrAttr.constructor.name === 'Attr' ? nodeOrAttr.name : nodeOrAttr.nodeName;
+  }
+
+  /***************************************************************************
+   *                            Tokenization                                 *
+   ***************************************************************************/
+  /**
+   * The XPath lexer is basically a single regular expression, along with
+   * some helper functions to pop different types.
+   */
+  var Stream = xpath.Stream = function Stream(str) {
+    this.original = this.str = str;
+    this.peeked = null;
+    // TODO: not really needed, but supposedly tokenizer also disambiguates
+    // a * b vs. node test *
+    this.prev = null;  // for debugging
+    this.prevprev = null;
+  }
+  Stream.prototype = {
+    peek: function() {
+      if (this.peeked) return this.peeked;
+      var m = this.re.exec(this.str);
+      if (!m) return null;
+      this.str = this.str.substr(m[0].length);
+      return this.peeked = m[1];
+    },
+    /** Peek 2 tokens ahead. */
+    peek2: function() {
+      this.peek();  // make sure this.peeked is set
+      var m = this.re.exec(this.str);
+      if (!m) return null;
+      return m[1];
+    },
+    pop: function() {
+      var r = this.peek();
+      this.peeked = null;
+      this.prevprev = this.prev;
+      this.prev = r;
+      return r;
+    },
+    trypop: function(tokens) {
+      var tok = this.peek();
+      if (tok === tokens) return this.pop();
+      if (Array.isArray(tokens)) {
+        for (var i = 0; i < tokens.length; ++i) {
+          var t = tokens[i];
+          if (t == tok) return this.pop();;
+        }
+      }
+    },
+    trypopfuncname: function() {
+      var tok = this.peek();
+      if (!this.isQnameRe.test(tok))
+        return null;
+      switch (tok) {
+        case 'comment': case 'text': case 'processing-instruction': case 'node':
+          return null;
+      }
+      if ('(' != this.peek2()) return null;
+      return this.pop();
+    },
+    trypopaxisname: function() {
+      var tok = this.peek();
+      switch (tok) {
+        case 'ancestor': case 'ancestor-or-self': case 'attribute':
+        case 'child': case 'descendant': case 'descendant-or-self':
+        case 'following': case 'following-sibling': case 'namespace':
+        case 'parent': case 'preceding': case 'preceding-sibling': case 'self':
+          if ('::' == this.peek2()) return this.pop();
+      }
+      return null;
+    },
+    trypopnametest: function() {
+      var tok = this.peek();
+      if ('*' === tok || this.startsWithNcNameRe.test(tok)) return this.pop();
+      return null;
+    },
+    trypopliteral: function() {
+      var tok = this.peek();
+      if (null == tok) return null;
+      var first = tok.charAt(0);
+      var last = tok.charAt(tok.length - 1);
+      if ('"' === first && '"' === last ||
+          "'" === first && "'" === last) {
+        this.pop();
+        return tok.substr(1, tok.length - 2);
+      }
+    },
+    trypopnumber: function() {
+      var tok = this.peek();
+      if (this.isNumberRe.test(tok)) return parseFloat(this.pop());
+      else return null;
+    },
+    trypopvarref: function() {
+      var tok = this.peek();
+      if (null == tok) return null;
+      if ('$' === tok.charAt(0)) return this.pop().substr(1);
+      else return null;
+    },
+    position: function() {
+      return this.original.length - this.str.length;
+    }
+  };
+  (function() {
+    // http://www.w3.org/TR/REC-xml-names/#NT-NCName
+    var nameStartCharsExceptColon =
+        'A-Z_a-z\xc0-\xd6\xd8-\xf6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF' +
+        '\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF' +
+        '\uFDF0-\uFFFD';  // JS doesn't support [#x10000-#xEFFFF]
+    var nameCharExceptColon = nameStartCharsExceptColon +
+        '\\-\\.0-9\xb7\u0300-\u036F\u203F-\u2040';
+    var ncNameChars = '[' + nameStartCharsExceptColon +
+        '][' + nameCharExceptColon + ']*'
+    // http://www.w3.org/TR/REC-xml-names/#NT-QName
+    var qNameChars = ncNameChars + '(?::' + ncNameChars + ')?';
+    var otherChars = '\\.\\.|[\\(\\)\\[\\].@,]|::';  // .. must come before [.]
+    var operatorChars =
+        'and|or|mod|div|' +
+        '//|!=|<=|>=|[*/|+\\-=<>]';  // //, !=, <=, >= before individual ones.
+    var literal = '"[^"]*"|' + "'[^']*'";
+    var numberChars = '[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+';
+    var variableReference = '\\$' + qNameChars;
+    var nameTestChars = '\\*|' + ncNameChars + ':\\*|' + qNameChars;
+    var optionalSpace = '[ \t\r\n]*';  // stricter than regexp \s.
+    var nodeType = 'comment|text|processing-instruction|node';
+    var re = new RegExp(
+        // numberChars before otherChars so that leading-decimal doesn't become .
+        '^' + optionalSpace + '(' + numberChars + '|' + otherChars + '|' +
+        nameTestChars + '|' + operatorChars + '|' + literal + '|' +
+        variableReference + ')'
+        // operatorName | nodeType | functionName | axisName are lumped into
+        // qName for now; we'll check them on pop.
+    );
+    Stream.prototype.re = re;
+    Stream.prototype.startsWithNcNameRe = new RegExp('^' + ncNameChars);
+    Stream.prototype.isQnameRe = new RegExp('^' + qNameChars + '$');
+    Stream.prototype.isNumberRe = new RegExp('^' + numberChars + '$');
+  })();
+
+  /***************************************************************************
+   *                               Parsing                                   *
+   ***************************************************************************/
+  var parse = xpath.parse = function parse(stream, a) {
+    var r = orExpr(stream,a);
+    var x, unparsed = [];
+    while (x = stream.pop()) {
+      unparsed.push(x);
+    }
+    if (unparsed.length)
+      throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                               'Position ' + stream.position() +
+                               ': Unparsed tokens: ' + unparsed.join(' '));
+    return r;
+  }
+
+  /**
+   * binaryL  ::= subExpr
+   *            | binaryL op subExpr
+   * so a op b op c becomes ((a op b) op c)
+   */
+  function binaryL(subExpr, stream, a, ops) {
+    var lhs = subExpr(stream, a);
+    if (lhs == null) return null;
+    var op;
+    while (op = stream.trypop(ops)) {
+      var rhs = subExpr(stream, a);
+      if (rhs == null)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected something after ' + op);
+      lhs = a.node(op, lhs, rhs);
+    }
+    return lhs;
+  }
+  /**
+   * Too bad this is never used. If they made a ** operator (raise to power),
+   ( we would use it.
+   * binaryR  ::= subExpr
+   *            | subExpr op binaryR
+   * so a op b op c becomes (a op (b op c))
+   */
+  function binaryR(subExpr, stream, a, ops) {
+    var lhs = subExpr(stream, a);
+    if (lhs == null) return null;
+    var op = stream.trypop(ops);
+    if (op) {
+      var rhs = binaryR(stream, a);
+      if (rhs == null)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected something after ' + op);
+      return a.node(op, lhs, rhs);
+    } else {
+      return lhs;// TODO
+    }
+  }
+  /** [1] LocationPath::= RelativeLocationPath | AbsoluteLocationPath
+   * e.g. a, a/b, //a/b
+   */
+  function locationPath(stream, a) {
+    return absoluteLocationPath(stream, a) ||
+           relativeLocationPath(null, stream, a);
+  }
+  /** [2] AbsoluteLocationPath::= '/' RelativeLocationPath? | AbbreviatedAbsoluteLocationPath
+   *  [10] AbbreviatedAbsoluteLocationPath::= '//' RelativeLocationPath
+   */
+  function absoluteLocationPath(stream, a) {
+    var op = stream.peek();
+    if ('/' === op || '//' === op) {
+      var lhs = a.node('Root');
+      return relativeLocationPath(lhs, stream, a, true);
+    } else {
+      return null;
+    }
+  }
+  /** [3] RelativeLocationPath::= Step | RelativeLocationPath '/' Step |
+   *                            | AbbreviatedRelativeLocationPath
+   *  [11] AbbreviatedRelativeLocationPath::= RelativeLocationPath '//' Step
+   * e.g. p/a, etc.
+   */
+  function relativeLocationPath(lhs, stream, a, isOnlyRootOk) {
+    if (null == lhs) {
+      lhs = step(stream, a);
+      if (null == lhs) return lhs;
+    }
+    var op;
+    while (op = stream.trypop(['/', '//'])) {
+      if ('//' === op) {
+        lhs = a.node('/', lhs,
+                     a.node('Axis', 'descendant-or-self', 'node', undefined));
+      }
+      var rhs = step(stream, a);
+      if (null == rhs && '/' === op && isOnlyRootOk) return lhs;
+      else isOnlyRootOk = false;
+      if (null == rhs)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected step after ' + op);
+      lhs = a.node('/', lhs, rhs);
+    }
+    return lhs;
+  }
+  /** [4] Step::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
+   *  [12] AbbreviatedStep::= '.' | '..'
+   * e.g. @href, self::p, p, a[@href], ., ..
+   */
+  function step(stream, a) {
+    var abbrStep = stream.trypop(['.', '..']);
+    if ('.' === abbrStep)  // A location step of . is short for self::node().
+      return a.node('Axis', 'self', 'node');
+    if ('..' === abbrStep)  // A location step of .. is short for parent::node()
+      return a.node('Axis', 'parent', 'node');
+
+    var axis = axisSpecifier(stream, a);
+    var nodeType = nodeTypeTest(stream, a);
+    var nodeName;
+    if (null == nodeType) nodeName = nodeNameTest(stream, a);
+    if (null == axis && null == nodeType && null == nodeName) return null;
+    if (null == nodeType && null == nodeName)
+        throw new XPathException(
+            XPathException.INVALID_EXPRESSION_ERR,
+            'Position ' + stream.position() +
+            ': Expected nodeTest after axisSpecifier ' + axis);
+    if (null == axis) axis = 'child';
+    if (null == nodeType) {
+      // When there's only a node name, then the node type is forced to be the
+      // principal node type of the axis.
+      // see http://www.w3.org/TR/xpath/#dt-principal-node-type
+      if ('attribute' === axis) nodeType = 'attribute';
+      else if ('namespace' === axis) nodeType = 'namespace';
+      else nodeType = 'element';
+    }
+    var lhs = a.node('Axis', axis, nodeType, nodeName);
+    var pred;
+    while (null != (pred = predicate(lhs, stream, a))) {
+      lhs = pred;
+    }
+    return lhs;
+  }
+  /** [5] AxisSpecifier::= AxisName '::' | AbbreviatedAxisSpecifier
+   *  [6] AxisName::= 'ancestor' | 'ancestor-or-self' | 'attribute' | 'child'
+   *                | 'descendant' | 'descendant-or-self' | 'following'
+   *                | 'following-sibling' | 'namespace' | 'parent' |
+   *                | 'preceding' | 'preceding-sibling' | 'self'
+   *  [13] AbbreviatedAxisSpecifier::= '@'?
+   */
+  function axisSpecifier(stream, a) {
+    var attr = stream.trypop('@');
+    if (null != attr) return 'attribute';
+    var axisName = stream.trypopaxisname();
+    if (null != axisName) {
+      var coloncolon = stream.trypop('::');
+      if (null == coloncolon)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Should not happen. Should be ::.');
+      return axisName;
+    }
+  }
+  /** [7] NodeTest::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
+   *  [38] NodeType::= 'comment' | 'text' | 'processing-instruction' | 'node'
+   * I've split nodeTypeTest from nodeNameTest for convenience.
+   */
+  function nodeTypeTest(stream, a) {
+    if ('(' !== stream.peek2()) {
+      return null;
+    }
+    var type = stream.trypop(['comment', 'text', 'processing-instruction', 'node']);
+    if (null != type) {
+      if (null == stream.trypop('('))
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Should not happen.');
+      var param = undefined;
+      if (type == 'processing-instruction') {
+        param = stream.trypopliteral();
+      }
+      if (null == stream.trypop(')'))
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected close parens.');
+      return type
+    }
+  }
+  function nodeNameTest(stream, a) {
+    var name = stream.trypopnametest();
+    if (name != null) return name;
+    else return null;
+  }
+  /** [8] Predicate::= '[' PredicateExpr ']'
+   *  [9] PredicateExpr::= Expr
+   */
+  function predicate(lhs, stream, a) {
+    if (null == stream.trypop('[')) return null;
+    var expr = orExpr(stream, a);
+    if (null == expr)
+      throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                               'Position ' + stream.position() +
+                               ': Expected expression after [');
+    if (null == stream.trypop(']'))
+      throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                               'Position ' + stream.position() +
+                               ': Expected ] after expression.');
+    return a.node('Predicate', lhs, expr);
+  }
+  /** [14] Expr::= OrExpr
+   */
+  /** [15] PrimaryExpr::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
+   * e.g. $x,  (3+4),  "hi",  32,  f(x)
+   */
+  function primaryExpr(stream, a) {
+    var x = stream.trypopliteral();
+    if (null == x)
+      x = stream.trypopnumber();
+    if (null != x) {
+      return x;
+    }
+    var varRef = stream.trypopvarref();
+    if (null != varRef) return a.node('VariableReference', varRef);
+    var funCall = functionCall(stream, a);
+    if (null != funCall) {
+      return funCall;
+    }
+    if (stream.trypop('(')) {
+      var e = orExpr(stream, a);
+      if (null == e)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected expression after (.');
+      if (null == stream.trypop(')'))
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected ) after expression.');
+      return e;
+    }
+    return null;
+  }
+  /** [16] FunctionCall::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
+   *  [17] Argument::= Expr
+   */
+  function functionCall(stream, a) {
+    var name = stream.trypopfuncname(stream, a);
+    if (null == name) return null;
+    if (null == stream.trypop('('))
+      throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                               'Position ' + stream.position() +
+                               ': Expected ( ) after function name.');
+    var params = [];
+    var first = true;
+    while (null == stream.trypop(')')) {
+      if (!first && null == stream.trypop(','))
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected , between arguments of the function.');
+      first = false;
+      var param = orExpr(stream, a);
+      if (param == null)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected expression as argument of function.');
+      params.push(param);
+    }
+    return a.node('FunctionCall', name, params);
+  }
+
+  /** [18] UnionExpr::= PathExpr | UnionExpr '|' PathExpr
+   */
+  function unionExpr(stream, a) { return binaryL(pathExpr, stream, a, '|'); }
+  /** [19] PathExpr ::= LocationPath
+   *                  | FilterExpr
+   *                  | FilterExpr '/' RelativeLocationPath
+   *                  | FilterExpr '//' RelativeLocationPath
+   * Unlike most other nodes, this one always generates a node because
+   * at this point all reverse nodesets must turn into a forward nodeset
+   */
+  function pathExpr(stream, a) {
+    // We have to do FilterExpr before LocationPath because otherwise
+    // LocationPath will eat up the name from a function call.
+    var filter = filterExpr(stream, a);
+    if (null == filter) {
+      var loc = locationPath(stream, a);
+      if (null == loc) {
+        throw new Error
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': The expression shouldn\'t be empty...');
+      }
+      return a.node('PathExpr', loc);
+    }
+    var rel = relativeLocationPath(filter, stream, a, false);
+    if (filter === rel) return rel;
+    else return a.node('PathExpr', rel);
+  }
+  /** [20] FilterExpr::= PrimaryExpr | FilterExpr Predicate
+   * aka. FilterExpr ::= PrimaryExpr Predicate*
+   */
+  function filterExpr(stream, a) {
+    var primary = primaryExpr(stream, a);
+    if (primary == null) return null;
+    var pred, lhs = primary;
+    while (null != (pred = predicate(lhs, stream, a))) {
+      lhs = pred;
+    }
+    return lhs;
+  }
+
+  /** [21] OrExpr::= AndExpr | OrExpr 'or' AndExpr
+   */
+  function orExpr(stream, a) {
+    var orig = (stream.peeked || '') + stream.str
+    var r = binaryL(andExpr, stream, a, 'or');
+    var now = (stream.peeked || '') + stream.str;
+    return r;
+  }
+  /** [22] AndExpr::= EqualityExpr | AndExpr 'and' EqualityExpr
+   */
+  function andExpr(stream, a) { return binaryL(equalityExpr, stream, a, 'and'); }
+  /** [23] EqualityExpr::= RelationalExpr | EqualityExpr '=' RelationalExpr
+   *                     | EqualityExpr '!=' RelationalExpr
+   */
+  function equalityExpr(stream, a) { return binaryL(relationalExpr, stream, a, ['=','!=']); }
+  /** [24] RelationalExpr::= AdditiveExpr | RelationalExpr '<' AdditiveExpr
+   *                       | RelationalExpr '>' AdditiveExpr
+   *                       | RelationalExpr '<=' AdditiveExpr
+   *                       | RelationalExpr '>=' AdditiveExpr
+   */
+  function relationalExpr(stream, a) { return binaryL(additiveExpr, stream, a, ['<','>','<=','>=']); }
+  /** [25] AdditiveExpr::= MultiplicativeExpr
+   *                     | AdditiveExpr '+' MultiplicativeExpr
+   *                     | AdditiveExpr '-' MultiplicativeExpr
+   */
+  function additiveExpr(stream, a) { return binaryL(multiplicativeExpr, stream, a, ['+','-']); }
+  /** [26] MultiplicativeExpr::= UnaryExpr
+   *                           | MultiplicativeExpr MultiplyOperator UnaryExpr
+   *                           | MultiplicativeExpr 'div' UnaryExpr
+   *                           | MultiplicativeExpr 'mod' UnaryExpr
+   */
+  function multiplicativeExpr(stream, a) { return binaryL(unaryExpr, stream, a, ['*','div','mod']); }
+  /** [27] UnaryExpr::= UnionExpr | '-' UnaryExpr
+   */
+  function unaryExpr(stream, a) {
+    if (stream.trypop('-')) {
+      var e = unaryExpr(stream, a);
+      if (null == e)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Expected unary expression after -');
+      return a.node('UnaryMinus', e);
+    }
+    else return unionExpr(stream, a);
+  }
+  var astFactory = {
+    node: function() {return Array.prototype.slice.call(arguments);}
+  };
+
+
+  /***************************************************************************
+   *                            Optimizations (TODO)                         *
+   ***************************************************************************/
+  /**
+   * Some things I've been considering:
+   * 1) a//b becomes a/descendant::b if there's no predicate that uses
+   *    position() or last()
+   * 2) axis[pred]: when pred doesn't use position, evaluate it just once per
+   *    node in the node-set rather than once per (node, position, last).
+   * For more optimizations, look up Gecko's optimizer:
+   * http://mxr.mozilla.org/mozilla-central/source/content/xslt/src/xpath/txXPathOptimizer.cpp
+   */
+  // TODO
+  function optimize(ast) {
+  }
+
+  /***************************************************************************
+   *                           Evaluation: axes                              *
+   ***************************************************************************/
+
+  /**
+   * Data types: For string, number, boolean, we just use Javascript types.
+   * Node-sets have the form
+   *    {nodes: [node, ...]}
+   * or {nodes: [node, ...], pos: [[1], [2], ...], lasts: [[1], [2], ...]}
+   *
+   * Most of the time, only the node is used and the position information is
+   * discarded. But if you use a predicate, we need to try every value of
+   * position and last in case the predicate calls position() or last().
+   */
+
+  /**
+   * The NodeMultiSet is a helper class to help generate
+   * {nodes:[], pos:[], lasts:[]} structures. It is useful for the
+   * descendant, descendant-or-self, following-sibling, and
+   * preceding-sibling axes for which we can use a stack to organize things.
+   */
+  function NodeMultiSet(isReverseAxis) {
+    this.nodes = [];
+    this.pos = [];
+    this.lasts = [];
+    this.nextPos = [];
+    this.seriesIndexes = [];  // index within nodes that each series begins.
+    this.isReverseAxis = isReverseAxis;
+    this._pushToNodes = isReverseAxis ? Array.prototype.unshift : Array.prototype.push;
+  }
+  NodeMultiSet.prototype = {
+    pushSeries: function pushSeries() {
+      this.nextPos.push(1);
+      this.seriesIndexes.push(this.nodes.length);
+    },
+    popSeries: function popSeries() {
+      console.assert(0 < this.nextPos.length, this.nextPos);
+      var last = this.nextPos.pop() - 1,
+          indexInPos = this.nextPos.length,
+          seriesBeginIndex = this.seriesIndexes.pop(),
+          seriesEndIndex = this.nodes.length;
+      for (var i = seriesBeginIndex; i < seriesEndIndex; ++i) {
+        console.assert(indexInPos < this.lasts[i].length);
+        console.assert(undefined === this.lasts[i][indexInPos]);
+        this.lasts[i][indexInPos] = last;
+      }
+    },
+    finalize: function() {
+      if (null == this.nextPos) return this;
+      console.assert(0 === this.nextPos.length);
+      var lastsJSON = JSON.stringify(this.lasts);
+      for (var i = 0; i < this.lasts.length; ++i) {
+        for (var j = 0; j < this.lasts[i].length; ++j) {
+          console.assert(null != this.lasts[i][j], i + ',' + j + ':' + lastsJSON);
+        }
+      }
+      this.pushSeries = this.popSeries = this.addNode = function() {
+        throw new Error('Already finalized.');
+      };
+      return this;
+    },
+    addNode: function addNode(node) {
+      console.assert(node);
+      this._pushToNodes.call(this.nodes, node)
+      this._pushToNodes.call(this.pos, this.nextPos.slice());
+      this._pushToNodes.call(this.lasts, new Array(this.nextPos.length));
+      for (var i = 0; i < this.nextPos.length; ++i) this.nextPos[i]++;
+    },
+    simplify: function() {
+      this.finalize();
+      return {nodes:this.nodes, pos:this.pos, lasts:this.lasts};
+    }
+  };
+  function eachContext(nodeMultiSet) {
+    var r = [];
+    for (var i = 0; i < nodeMultiSet.nodes.length; i++) {
+      var node = nodeMultiSet.nodes[i];
+      if (!nodeMultiSet.pos) {
+        r.push({nodes:[node], pos: [[i + 1]], lasts: [[nodeMultiSet.nodes.length]]});
+      } else {
+        for (var j = 0; j < nodeMultiSet.pos[i].length; ++j) {
+          r.push({nodes:[node], pos: [[nodeMultiSet.pos[i][j]]], lasts: [[nodeMultiSet.lasts[i][j]]]});
+        }
+      }
+    }
+    return r;
+  }
+  /** Matcher used in the axes.
+   */
+  function NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase) {
+    this.nodeTypeNum = nodeTypeNum;
+    this.nodeName = nodeName;
+    this.shouldLowerCase = shouldLowerCase;
+    this.nodeNameTest =
+      null == nodeName ? this._alwaysTrue :
+      shouldLowerCase ? this._nodeNameLowerCaseEquals :
+      this._nodeNameEquals;
+  }
+  NodeMatcher.prototype = {
+    matches: function matches(node) {
+      if (0 === this.nodeTypeNum || this._nodeTypeMatches(node)) {
+        return this.nodeNameTest(getNodeName(node));
+      }
+
+      return false;
+    },
+    _nodeTypeMatches(nodeOrAttr) {
+      if (nodeOrAttr.constructor.name === 'Attr' && this.nodeTypeNum === 2) {
+        return true;
+      }
+      return nodeOrAttr.nodeType === this.nodeTypeNum;
+    },
+    _alwaysTrue: function(name) {return true;},
+    _nodeNameEquals: function _nodeNameEquals(name) {
+      return this.nodeName === name;
+    },
+    _nodeNameLowerCaseEquals: function _nodeNameLowerCaseEquals(name) {
+      return this.nodeName === name.toLowerCase();
+    }
+  };
+
+  function followingSiblingHelper(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, shift, peek, followingNode, andSelf, isReverseAxis) {
+    var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+    var nodeMultiSet = new NodeMultiSet(isReverseAxis);
+    while (0 < nodeList.length) {  // can be if for following, preceding
+      var node = shift.call(nodeList);
+      console.assert(node != null);
+      node = followingNode(node);
+      nodeMultiSet.pushSeries();
+      var numPushed = 1;
+      while (null != node) {
+        if (! andSelf && matcher.matches(node))
+          nodeMultiSet.addNode(node);
+        if (node === peek.call(nodeList)) {
+          shift.call(nodeList);
+          nodeMultiSet.pushSeries();
+          numPushed++;
+        }
+        if (andSelf && matcher.matches(node))
+          nodeMultiSet.addNode(node);
+        node = followingNode(node);
+      }
+      while (0 < numPushed--)
+        nodeMultiSet.popSeries();
+    }
+    return nodeMultiSet;
+  }
+
+  /** Returns the next non-descendant node in document order.
+   * This is the first node in following::node(), if node is the context.
+   */
+  function followingNonDescendantNode(node) {
+    if (node.ownerElement) {
+      if (node.ownerElement.firstChild)
+        return node.ownerElement.firstChild;
+      node = node.ownerElement;
+    }
+    do {
+      if (node.nextSibling) return node.nextSibling;
+    } while (node = node.parentNode);
+    return null;
+  }
+
+  /** Returns the next node in a document-order depth-first search.
+   * See the definition of document order[1]:
+   *   1) element
+   *   2) namespace nodes
+   *   3) attributes
+   *   4) children
+   *   [1]: http://www.w3.org/TR/xpath/#dt-document-order
+   */
+  function followingNode(node) {
+    if (node.ownerElement)  // attributes: following node of element.
+      node = node.ownerElement;
+    if (null != node.firstChild)
+      return node.firstChild;
+    do {
+      if (null != node.nextSibling) {
+        return node.nextSibling;
+      }
+      node = node.parentNode;
+    } while (node);
+    return null;
+  }
+  /** Returns the previous node in document order (excluding attributes
+   * and namespace nodes).
+   */
+  function precedingNode(node) {
+    if (node.ownerElement)
+      return node.ownerElement;
+    if (null != node.previousSibling) {
+      node = node.previousSibling;
+      while (null != node.lastChild) {
+        node = node.lastChild;
+      }
+      return node;
+    }
+    if (null != node.parentNode) {
+      return node.parentNode;
+    }
+    return null;
+  }
+  /** This axis is inefficient if there are many nodes in the nodeList.
+   * But I think it's a pretty useless axis so it's ok. */
+  function followingHelper(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+    var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+    var nodeMultiSet = new NodeMultiSet(false);
+    var cursor = nodeList[0];
+    var unorderedFollowingStarts = [];
+    for (var i = 0; i < nodeList.length; i++) {
+      var node = nodeList[i];
+      var start = followingNonDescendantNode(node);
+      if (start)
+        unorderedFollowingStarts.push(start);
+    }
+    if (0 === unorderedFollowingStarts.length)
+      return {nodes:[]};
+    var pos = [], nextPos = [];
+    var started = 0;
+    while (cursor = followingNode(cursor)) {
+      for (var i = unorderedFollowingStarts.length - 1; i >= 0; i--){
+        if (cursor === unorderedFollowingStarts[i]) {
+          nodeMultiSet.pushSeries();
+          unorderedFollowingStarts.splice(i,i+1);
+          started++;
+        }
+      }
+      if (started && matcher.matches(cursor)) {
+        nodeMultiSet.addNode(cursor);
+      }
+    }
+    console.assert(0 === unorderedFollowingStarts.length);
+    for (var i = 0; i < started; i++)
+      nodeMultiSet.popSeries();
+    return nodeMultiSet.finalize();
+  }
+  function precedingHelper(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+    var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+    var cursor = nodeList.pop();
+    if (null == cursor) return {nodes:{}};
+    var r = {nodes:[], pos:[], lasts:[]};
+    var nextParents = [cursor.parentNode || cursor.ownerElement], nextPos = [1];
+    while (cursor = precedingNode(cursor)) {
+      if (cursor === nodeList[nodeList.length - 1]) {
+        nextParents.push(nodeList.pop());
+        nextPos.push(1);
+      }
+      var matches = matcher.matches(cursor);
+      var pos, someoneUsed = false;
+      if (matches)
+        pos = nextPos.slice();
+
+      for (var i = 0; i < nextParents.length; ++i) {
+        if (cursor === nextParents[i]) {
+          nextParents[i] = cursor.parentNode || cursor.ownerElement;
+          if (matches) {
+            pos[i] = null;
+          }
+        } else {
+          if (matches) {
+            pos[i] = nextPos[i]++;
+            someoneUsed = true;
+          }
+        }
+      }
+      if (someoneUsed) {
+        r.nodes.unshift(cursor);
+        r.pos.unshift(pos);
+      }
+    }
+    for (var i = 0; i < r.pos.length; ++i) {
+      var lasts = [];
+      r.lasts.push(lasts);
+      for (var j = r.pos[i].length - 1; j >= 0; j--) {
+        if (null == r.pos[i][j]) {
+          r.pos[i].splice(j, j+1);
+        } else {
+          lasts.unshift(nextPos[j] - 1);
+        }
+      }
+    }
+    return r;
+  }
+
+  /** node-set, axis -> node-set */
+  function descendantDfs(nodeMultiSet, node, remaining, matcher, andSelf, attrIndices, attrNodes) {
+    while (0 < remaining.length && null != remaining[0].ownerElement) {
+      var attr = remaining.shift();
+      if (andSelf && matcher.matches(attr)) {
+        attrNodes.push(attr);
+        attrIndices.push(nodeMultiSet.nodes.length);
+      }
+    }
+    if (null != node && !andSelf) {
+      if (matcher.matches(node))
+        nodeMultiSet.addNode(node);
+    }
+    var pushed = false;
+    if (null == node) {
+      if (0 === remaining.length) return;
+      node = remaining.shift();
+      nodeMultiSet.pushSeries();
+      pushed = true;
+    } else if (0 < remaining.length && node === remaining[0]) {
+      nodeMultiSet.pushSeries();
+      pushed = true;
+      remaining.shift();
+    }
+    if (andSelf) {
+      if (matcher.matches(node))
+        nodeMultiSet.addNode(node);
+    }
+    // TODO: use optimization. Also try element.getElementsByTagName
+    // var nodeList = 1 === nodeTypeNum && null != node.children ? node.children : node.childNodes;
+    var nodeList = node.childNodes;
+    for (var j = 0; j < nodeList.length; ++j) {
+      var child = nodeList[j];
+      descendantDfs(nodeMultiSet, child, remaining, matcher, andSelf, attrIndices, attrNodes);
+    }
+    if (pushed) {
+      nodeMultiSet.popSeries();
+    }
+  }
+  function descenantHelper(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, andSelf) {
+    var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+    var nodeMultiSet = new NodeMultiSet(false);
+    var attrIndices = [], attrNodes = [];
+    while (0 < nodeList.length) {
+      // var node = nodeList.shift();
+      descendantDfs(nodeMultiSet, null, nodeList, matcher, andSelf, attrIndices, attrNodes);
+    }
+    nodeMultiSet.finalize();
+    for (var i = attrNodes.length-1; i >= 0; --i) {
+      nodeMultiSet.nodes.splice(attrIndices[i], attrIndices[i], attrNodes[i]);
+      nodeMultiSet.pos.splice(attrIndices[i], attrIndices[i], [1]);
+      nodeMultiSet.lasts.splice(attrIndices[i], attrIndices[i], [1]);
+    }
+    return nodeMultiSet;
+  }
+  /**
+   */
+  function ancestorHelper(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, andSelf) {
+    var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+    var ancestors = []; // array of non-empty arrays of matching ancestors
+    for (var i = 0; i < nodeList.length; ++i) {
+      var node = nodeList[i];
+      var isFirst = true;
+      var a = [];
+      while (null != node) {
+        if (!isFirst || andSelf) {
+          if (matcher.matches(node))
+            a.push(node);
+        }
+        isFirst = false;
+        node = node.parentNode || node.ownerElement;
+      }
+      if (0 < a.length)
+        ancestors.push(a);
+    }
+    var lasts = [];
+    for (var i = 0; i < ancestors.length; ++i) lasts.push(ancestors[i].length);
+    var nodeMultiSet = new NodeMultiSet(true);
+    var newCtx = {nodes:[], pos:[], lasts:[]};
+    while (0 < ancestors.length) {
+      var pos = [ancestors[0].length];
+      var last = [lasts[0]];
+      var node = ancestors[0].pop();
+      for (var i = ancestors.length - 1; i > 0; --i) {
+        if (node === ancestors[i][ancestors[i].length - 1]) {
+          pos.push(ancestors[i].length);
+          last.push(lasts[i]);
+          ancestors[i].pop();
+          if (0 === ancestors[i].length) {
+            ancestors.splice(i, i+1);
+            lasts.splice(i, i+1);
+          }
+        }
+      }
+      if (0 === ancestors[0].length) {
+        ancestors.shift();
+        lasts.shift();
+      }
+      newCtx.nodes.push(node);
+      newCtx.pos.push(pos);
+      newCtx.lasts.push(last);
+    }
+    return newCtx;
+  }
+  /** Helper function for sortDocumentOrder. Returns a list of indices, from the
+   * node to the root, of positions within parent.
+   * For convenience, the node is the first element of the array.
+   */
+  function addressVector(node) {
+    var r = [node];
+    if (null != node.ownerElement) {
+      node = node.ownerElement;
+      r.push(-1);
+    }
+    while (null != node) {
+      var i = 0;
+      while (null != node.previousSibling) {
+        node = node.previousSibling;
+        i++;
+      }
+      r.push(i);
+      node = node.parentNode
+    }
+    return r;
+  }
+  function addressComparator(a, b) {
+    var minlen = Math.min(a.length - 1, b.length - 1),  // not including [0]=node
+        alen = a.length,
+        blen = b.length;
+    if (a[0] === b[0]) return 0;
+    var c;
+    for (var i = 0; i < minlen; ++i) {
+      c = a[alen - i - 1] - b[blen - i - 1];
+      if (0 !== c)
+        break;
+    }
+    if (null == c || 0 === c) {
+      // All equal until one of the nodes. The longer one is the descendant.
+      c = alen - blen;
+    }
+    if (0 === c)
+      c = getNodeName(a) - getNodeName(b);
+    if (0 === c)
+      c = 1;
+    return c;
+  }
+  var sortUniqDocumentOrder = xpath.sortUniqDocumentOrder = function(nodes) {
+    var a = [];
+    for (var i = 0; i < nodes.length; i++) {
+      var node = nodes[i];
+      var v = addressVector(node);
+      a.push(v);
+    }
+    a.sort(addressComparator);
+    var b = [];
+    for (var i = 0; i < a.length; i++) {
+      if (0 < i && a[i][0] === a[i - 1][0])
+        continue;
+      b.push(a[i][0]);
+    }
+    return b;
+  }
+  /** Sort node multiset. Does not do any de-duping. */
+  function sortNodeMultiSet(nodeMultiSet) {
+    var a = [];
+    for (var i = 0; i < nodeMultiSet.nodes.length; i++) {
+      var v = addressVector(nodeMultiSet.nodes[i]);
+      a.push({v:v, n:nodeMultiSet.nodes[i],
+              p:nodeMultiSet.pos[i], l:nodeMultiSet.lasts[i]});
+    }
+    a.sort(compare);
+    var r = {nodes:[], pos:[], lasts:[]};
+    for (var i = 0; i < a.length; ++i) {
+      r.nodes.push(a[i].n);
+      r.pos.push(a[i].p);
+      r.lasts.push(a[i].l);
+    }
+    function compare(x, y) {
+      return addressComparator(x.v, y.v);
+    }
+    return r;
+  }
+  /** Returns an array containing all the ancestors down to a node.
+   * The array starts with document.
+   */
+  function nodeAndAncestors(node) {
+    var ancestors = [node];
+    var p = node;
+    while (p = p.parentNode || p.ownerElement) {
+      ancestors.unshift(p);
+    }
+    return ancestors;
+  }
+  function compareSiblings(a, b) {
+    if (a === b) return 0;
+    var c = a;
+    while (c = c.previousSibling) {
+      if (c === b)
+        return 1;  // b < a
+    }
+    c = b;
+    while (c = c.previousSibling) {
+      if (c === a)
+        return -1;  // a < b
+    }
+    throw new Error('a and b are not siblings: ' + xpath.stringifyObject(a) + ' vs ' + xpath.stringifyObject(b));
+  }
+  /** The merge in merge-sort.*/
+  function mergeNodeLists(x, y) {
+    var a, b, aanc, banc, r = [];
+    if ('object' !== typeof x)
+      throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                               'Invalid LHS for | operator ' +
+                               '(expected node-set): ' + x);
+    if ('object' !== typeof y)
+      throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                               'Invalid LHS for | operator ' +
+                               '(expected node-set): ' + y);
+    while (true) {
+      if (null == a) {
+        a = x.shift();
+        if (null != a)
+          aanc = addressVector(a);
+      }
+      if (null == b) {
+        b = y.shift();
+        if (null != b)
+          banc = addressVector(b);
+      }
+      if (null == a || null == b) break;
+      var c = addressComparator(aanc, banc);
+      if (c < 0) {
+        r.push(a);
+        a = null;
+        aanc = null;
+      } else if (c > 0) {
+        r.push(b);
+        b = null;
+        banc = null;
+      } else if (getNodeName(a) < getNodeName(b)) {  // attributes
+        r.push(a);
+        a = null;
+        aanc = null;
+      } else if (getNodeName(a) > getNodeName(b)) {  // attributes
+        r.push(b);
+        b = null;
+        banc = null;
+      } else if (a !== b) {
+        // choose b arbitrarily
+        r.push(b);
+        b = null;
+        banc = null;
+      } else {
+        console.assert(a === b, c);
+        // just skip b without pushing it.
+        b = null;
+        banc = null;
+      }
+    }
+    while (a) {
+      r.push(a);
+      a = x.shift();
+    }
+    while (b) {
+      r.push(b);
+      b = y.shift();
+    }
+    return r;
+  }
+  function comparisonHelper(test, x, y, isNumericComparison) {
+    var coersion;
+    if (isNumericComparison)
+      coersion = fn.number;
+    else coersion =
+      'boolean' === typeof x || 'boolean' === typeof y ? fn['boolean'] :
+      'number' === typeof x || 'number' === typeof y ? fn.number :
+      fn.string;
+    if ('object' === typeof x && 'object' === typeof y) {
+      var aMap = {};
+      for (var i = 0; i < x.nodes.length; ++i) {
+        var xi = coersion({nodes:[x.nodes[i]]});
+        for (var j = 0; j < y.nodes.length; ++j) {
+          var yj = coersion({nodes:[y.nodes[j]]});
+          if (test(xi, yj)) return true;
+        }
+      }
+      return false;
+    } else if ('object' === typeof x && x.nodes && x.nodes.length) {
+      for (var i = 0; i < x.nodes.length; ++i) {
+        var xi = coersion({nodes:[x.nodes[i]]}), yc = coersion(y);
+        if (test(xi, yc))
+          return true;
+      }
+      return false;
+    } else if ('object' === typeof y && x.nodes && x.nodes.length) {
+      for (var i = 0; i < x.nodes.length; ++i) {
+        var yi = coersion({nodes:[y.nodes[i]]}), xc = coersion(x);
+        if (test(xc, yi))
+          return true;
+      }
+      return false;
+    } else {
+      var xc = coersion(x), yc = coersion(y);
+      return test(xc, yc);
+    }
+  }
+  var axes = xpath.axes = {
+    'ancestor':
+      function ancestor(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return ancestorHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, false);
+      },
+    'ancestor-or-self':
+      function ancestorOrSelf(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return ancestorHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, true);
+      },
+    'attribute':
+      function attribute(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        // TODO: figure out whether positions should be undefined here.
+        var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+        var nodeMultiSet = new NodeMultiSet(false);
+        if (null != nodeName) {
+          // TODO: with namespace
+          for (var i = 0; i < nodeList.length; ++i) {
+            var node = nodeList[i];
+            if (null == node.getAttributeNode)
+              continue;  // only Element has .getAttributeNode
+            var attr = node.getAttributeNode(nodeName);
+            if (null != attr && matcher.matches(attr)) {
+              nodeMultiSet.pushSeries();
+              nodeMultiSet.addNode(attr);
+              nodeMultiSet.popSeries();
+            }
+          }
+        } else {
+          for (var i = 0; i < nodeList.length; ++i) {
+            var node = nodeList[i];
+            if (null != node.attributes) {
+              nodeMultiSet.pushSeries();
+              for (var j = 0; j < node.attributes.length; j++) {  // all nodes have .attributes
+                var attr = node.attributes[j];
+                if (matcher.matches(attr))  // TODO: I think this check is unnecessary
+                  nodeMultiSet.addNode(attr);
+              }
+              nodeMultiSet.popSeries();
+            }
+          }
+        }
+        return nodeMultiSet.finalize();
+      },
+    'child':
+      function child(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+        var nodeMultiSet = new NodeMultiSet(false);
+        for (var i = 0; i < nodeList.length; ++i) {
+          var n = nodeList[i];
+          if (n.ownerElement)  // skip attribute nodes' text child.
+            continue;
+          if (n.childNodes) {
+            nodeMultiSet.pushSeries();
+            var childList = 1 === nodeTypeNum && null != n.children ?
+                n.children : n.childNodes;
+            for (var j = 0; j < childList.length; ++j) {
+              var child = childList[j];
+              if (matcher.matches(child)) {
+                nodeMultiSet.addNode(child);
+              }
+              // don't have to do de-duping because children have parent,
+              // which are current context.
+            }
+            nodeMultiSet.popSeries();
+          }
+        }
+        nodeMultiSet.finalize();
+        return sortNodeMultiSet(nodeMultiSet);
+      },
+    'descendant':
+      function descenant(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return descenantHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, false);
+      },
+    'descendant-or-self':
+      function descenantOrSelf(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return descenantHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase, true);
+      },
+    'following':
+      function following(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return followingHelper(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase);
+      },
+    'following-sibling':
+      function followingSibling(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return followingSiblingHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase,
+          Array.prototype.shift, function() {return this[0];},
+          function(node) {return node.nextSibling;});
+      },
+    'namespace':
+      function namespace(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        // TODO
+      },
+    'parent':
+      function parent(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+        var nodes = [], pos = [];
+        for (var i = 0; i < nodeList.length; ++i) {
+          var parent = nodeList[i].parentNode || nodeList[i].ownerElement;
+          if (null == parent)
+            continue;
+          if (!matcher.matches(parent))
+            continue;
+          if (nodes.length > 0 && parent === nodes[nodes.length-1])
+            continue;
+          nodes.push(parent);
+          pos.push([1]);
+        }
+        return {nodes:nodes, pos:pos, lasts:pos};
+      },
+    'preceding':
+      function preceding(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return precedingHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase);
+      },
+    'preceding-sibling':
+      function precedingSibling(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        return followingSiblingHelper(
+          nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase,
+          Array.prototype.pop, function() {return this[this.length-1];},
+          function(node) {return node.previousSibling},
+          false, true);
+      },
+    'self':
+      function self(nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase) {
+        var nodes = [], pos = [];
+        var matcher = new NodeMatcher(nodeTypeNum, nodeName, shouldLowerCase);
+        for (var i = 0; i < nodeList.length; ++i) {
+          if (matcher.matches(nodeList[i])) {
+            nodes.push(nodeList[i]);
+            pos.push([1]);
+          }
+        }
+        return {nodes: nodes, pos: pos, lasts: pos}
+      }
+  };
+
+  /***************************************************************************
+   *                         Evaluation: functions                           *
+   ***************************************************************************/
+  var fn = {
+    'number': function number(optObject) {
+      if ('number' === typeof optObject)
+        return optObject;
+      if ('string' === typeof optObject)
+        return parseFloat(optObject);  // note: parseFloat(' ') -> NaN, unlike +' ' -> 0.
+      if ('boolean' === typeof optObject)
+        return +optObject;
+      return fn.number(fn.string.call(this, optObject));  // for node-sets
+    },
+    'string': function string(optObject) {
+      if (null == optObject)
+        return fn.string(this);
+      if ('string' === typeof optObject || 'boolean' === typeof optObject ||
+          'number' === typeof optObject)
+        return '' + optObject;
+      if (0 == optObject.nodes.length) return '';
+      if (null != optObject.nodes[0].textContent)
+        return optObject.nodes[0].textContent;
+      return optObject.nodes[0].nodeValue;
+    },
+    'boolean': function booleanVal(x) {
+      return 'object' === typeof x ? x.nodes.length > 0 : !!x;
+    },
+    'last': function last() {
+      console.assert(Array.isArray(this.pos));
+      console.assert(Array.isArray(this.lasts));
+      console.assert(1 === this.pos.length);
+      console.assert(1 === this.lasts.length);
+      console.assert(1 === this.lasts[0].length);
+      return this.lasts[0][0];
+    },
+    'position': function position() {
+      console.assert(Array.isArray(this.pos));
+      console.assert(Array.isArray(this.lasts));
+      console.assert(1 === this.pos.length);
+      console.assert(1 === this.lasts.length);
+      console.assert(1 === this.pos[0].length);
+      return this.pos[0][0];
+    },
+    'count': function count(nodeSet) {
+      if ('object' !== typeof nodeSet)
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Position ' + stream.position() +
+                                 ': Function count(node-set) ' +
+                                 'got wrong argument type: ' + nodeSet);
+      return nodeSet.nodes.length;
+    },
+    'id': function id(object) {
+      var r = {nodes: []};
+      var doc = this.nodes[0].ownerDocument || this.nodes[0];
+      console.assert(doc);
+      var ids;
+      if ('object' === typeof object) {
+        // for node-sets, map id over each node value.
+        ids = [];
+        for (var i = 0; i < object.nodes.length; ++i) {
+          var idNode = object.nodes[i];
+          var idsString = fn.string({nodes:[idNode]});
+          var a = idsString.split(/[ \t\r\n]+/g);
+          Array.prototype.push.apply(ids, a);
+        }
+      } else {
+        var idsString = fn.string(object);
+        var a = idsString.split(/[ \t\r\n]+/g);
+        ids = a;
+      }
+      for (var i = 0; i < ids.length; ++i) {
+        var id = ids[i];
+        if (0 === id.length)
+          continue;
+        var node = doc.getElementById(id);
+        if (null != node)
+          r.nodes.push(node);
+      }
+      r.nodes = sortUniqDocumentOrder(r.nodes);
+      return r;
+    },
+    'local-name': function(nodeSet) {
+      if (null == nodeSet)
+        return fn.name(this);
+      if (null == nodeSet.nodes) {
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'argument to name() must be a node-set. got ' + nodeSet);
+      }
+      // TODO: namespaced version
+      return nodeSet.nodes[0].localName;
+    },
+    'namespace-uri': function(nodeSet) {
+      // TODO
+      throw new Error('not implemented yet');
+    },
+    'name': function(nodeSet) {
+      if (null == nodeSet)
+        return fn.name(this);
+      if (null == nodeSet.nodes) {
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'argument to name() must be a node-set. got ' + nodeSet);
+      }
+      return nodeSet.nodes[0].name;
+    },
+    'concat': function concat(x) {
+      var l = [];
+      for (var i = 0; i < arguments.length; ++i) {
+        l.push(fn.string(arguments[i]));
+      }
+      return l.join('');
+    },
+    'starts-with': function startsWith(a, b) {
+      var as = fn.string(a), bs = fn.string(b);
+      return as.substr(0, bs.length) === bs;
+    },
+    'contains': function contains(a, b) {
+      var as = fn.string(a), bs = fn.string(b);
+      var i = as.indexOf(bs);
+      if (-1 === i) return false;
+      return true;
+    },
+    'substring-before': function substringBefore(a, b) {
+      var as = fn.string(a), bs = fn.string(b);
+      var i = as.indexOf(bs);
+      if (-1 === i) return '';
+      return as.substr(0, i);
+    },
+    'substring-after': function substringBefore(a, b) {
+      var as = fn.string(a), bs = fn.string(b);
+      var i = as.indexOf(bs);
+      if (-1 === i) return '';
+      return as.substr(i + bs.length);
+    },
+    'substring': function substring(string, start, optEnd) {
+      if (null == string || null == start) {
+        throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                 'Must be at least 2 arguments to string()');
+      }
+      var sString = fn.string(string),
+          iStart = fn.round(start),
+          iEnd = optEnd == null ? null : fn.round(optEnd);
+      // Note that xpath string positions user 1-based index
+      if (iEnd == null)
+        return sString.substr(iStart - 1);
+      else
+        return sString.substr(iStart - 1, iEnd);
+    },
+    'string-length': function stringLength(optString) {
+      return fn.string.call(this, optString).length;
+    },
+    'normalize-space': function normalizeSpace(optString) {
+      var s = fn.string.call(this, optString);
+      return s.replace(/[ \t\r\n]+/g, ' ').replace(/^ | $/g, '');
+    },
+    'translate': function translate(string, from, to) {
+      var sString = fn.string.call(this, string),
+          sFrom = fn.string(from),
+          sTo = fn.string(to);
+      var eachCharRe = [];
+      var map = {};
+      for (var i = 0; i < sFrom.length; ++i) {
+        var c = sFrom.charAt(i);
+        map[c] = sTo.charAt(i);  // returns '' if beyond length of sTo.
+        // copied from goog.string.regExpEscape in the Closure library.
+        eachCharRe.push(
+          c.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
+            replace(/\x08/g, '\\x08'));
+      }
+      var re = new RegExp(eachCharRe.join('|'), 'g');
+      return sString.replace(re, function(c) {return map[c];});
+    },
+    /// Boolean functions
+    'not': function not(x) {
+      var bx = fn['boolean'](x);
+      return !bx;
+    },
+    'true': function trueVal() { return true; },
+    'false': function falseVal() { return false; },
+    // TODO
+    'lang': function lang(string) { throw new Error('Not implemented');},
+    'sum': function sum(optNodeSet) {
+      if (null == optNodeSet) return fn.sum(this);
+      // for node-sets, map id over each node value.
+      var sum = 0;
+      for (var i = 0; i < optNodeSet.nodes.length; ++i) {
+        var node = optNodeSet.nodes[i];
+        var x = fn.number({nodes:[node]});
+        sum += x;
+      }
+      return sum;
+    },
+    'floor': function floor(number) {
+      return Math.floor(fn.number(number));
+    },
+    'ceiling': function ceiling(number) {
+      return Math.ceil(fn.number(number));
+    },
+    'round': function round(number) {
+      return Math.round(fn.number(number));
+    }
+  };
+  /***************************************************************************
+   *                         Evaluation: operators                           *
+   ***************************************************************************/
+  var more = {
+    UnaryMinus: function(x) { return -fn.number(x); },
+    '+': function(x, y) { return fn.number(x) + fn.number(y); },
+    '-': function(x, y) { return fn.number(x) - fn.number(y); },
+    '*': function(x, y) { return fn.number(x) * fn.number(y); },
+    'div': function(x, y) { return fn.number(x) / fn.number(y); },
+    'mod': function(x, y) { return fn.number(x) % fn.number(y); },
+    '<': function(x, y) {
+      return comparisonHelper(function(x, y) { return fn.number(x) < fn.number(y);}, x, y, true);
+    },
+    '<=': function(x, y) {
+      return comparisonHelper(function(x, y) { return fn.number(x) <= fn.number(y);}, x, y, true);
+    },
+    '>':  function(x, y) {
+      return comparisonHelper(function(x, y) { return fn.number(x) > fn.number(y);}, x, y, true);
+    },
+    '>=': function(x, y) {
+      return comparisonHelper(function(x, y) { return fn.number(x) >= fn.number(y);}, x, y, true);
+    },
+    'and': function(x, y) { return fn['boolean'](x) && fn['boolean'](y); },
+    'or': function(x, y) { return fn['boolean'](x) || fn['boolean'](y); },
+    '|': function(x, y) { return {nodes: mergeNodeLists(x.nodes, y.nodes)}; },
+    '=': function(x, y) {
+      // optimization for two node-sets case: avoid n^2 comparisons.
+      if ('object' === typeof x && 'object' === typeof y) {
+        var aMap = {};
+        for (var i = 0; i < x.nodes.length; ++i) {
+          var s = fn.string({nodes:[x.nodes[i]]});
+          aMap[s] = true;
+        }
+        for (var i = 0; i < y.nodes.length; ++i) {
+          var s = fn.string({nodes:[y.nodes[i]]});
+          if (aMap[s]) return true;
+        }
+        return false;
+      } else {
+        return comparisonHelper(function(x, y) {return x === y;}, x, y);
+      }
+    },
+    '!=': function(x, y) {
+      // optimization for two node-sets case: avoid n^2 comparisons.
+      if ('object' === typeof x && 'object' === typeof y) {
+        if (0 === x.nodes.length || 0 === y.nodes.length) return false;
+        var aMap = {};
+        for (var i = 0; i < x.nodes.length; ++i) {
+          var s = fn.string({nodes:[x.nodes[i]]});
+          aMap[s] = true;
+        }
+        for (var i = 0; i < y.nodes.length; ++i) {
+          var s = fn.string({nodes:[y.nodes[i]]});
+          if (!aMap[s]) return true;
+        }
+        return false;
+      } else {
+        return comparisonHelper(function(x, y) {return x !== y;}, x, y);
+      }
+    }
+  };
+  var nodeTypes = xpath.nodeTypes = {
+    'node': 0,
+    'attribute': 2,
+    'comment': 8, // this.doc.COMMENT_NODE,
+    'text': 3, // this.doc.TEXT_NODE,
+    'processing-instruction': 7, // this.doc.PROCESSING_INSTRUCTION_NODE,
+    'element': 1  //this.doc.ELEMENT_NODE
+  };
+  /** For debugging and unit tests: returnjs a stringified version of the
+   * argument. */
+  var stringifyObject = xpath.stringifyObject = function stringifyObject(ctx) {
+    var seenKey = 'seen' + Math.floor(Math.random()*1000000000);
+    return JSON.stringify(helper(ctx));
+
+    function helper(ctx) {
+      if (Array.isArray(ctx)) {
+        return ctx.map(function(x) {return helper(x);});
+      }
+      if ('object' !== typeof ctx) return ctx;
+      if (null == ctx) return ctx;
+    //  if (ctx.toString) return ctx.toString();
+      if (null != ctx.outerHTML) return ctx.outerHTML;
+      if (null != ctx.nodeValue) return ctx.nodeName + '=' + ctx.nodeValue;
+      if (ctx[seenKey]) return '[circular]';
+      ctx[seenKey] = true;
+      var nicer = {};
+      for (var key in ctx) {
+        if (seenKey === key)
+          continue;
+        try {
+          nicer[key] = helper(ctx[key]);
+        } catch (e) {
+          nicer[key] = '[exception: ' + e.message + ']';
+        }
+      }
+      delete ctx[seenKey];
+      return nicer;
+    }
+  }
+  var Evaluator = xpath.Evaluator = function Evaluator(doc) {
+    this.doc = doc;
+  }
+  Evaluator.prototype = {
+    val: function val(ast, ctx) {
+      console.assert(ctx.nodes);
+
+      if ('number' === typeof ast || 'string' === typeof ast) return ast;
+      if (more[ast[0]]) {
+        var evaluatedParams = [];
+        for (var i = 1; i < ast.length; ++i) {
+          evaluatedParams.push(this.val(ast[i], ctx));
+        }
+        var r = more[ast[0]].apply(ctx, evaluatedParams);
+        return r;
+      }
+      switch (ast[0]) {
+        case 'Root': return {nodes: [this.doc]};
+        case 'FunctionCall':
+          var functionName = ast[1], functionParams = ast[2];
+          if (null == fn[functionName])
+            throw new XPathException(XPathException.INVALID_EXPRESSION_ERR,
+                                     'Unknown function: ' + functionName);
+          var evaluatedParams = [];
+          for (var i = 0; i < functionParams.length; ++i) {
+            evaluatedParams.push(this.val(functionParams[i], ctx));
+          }
+          var r = fn[functionName].apply(ctx, evaluatedParams);
+          return r;
+        case 'Predicate':
+          var lhs = this.val(ast[1], ctx);
+          var ret = {nodes: []};
+          var contexts = eachContext(lhs);
+          for (var i = 0; i < contexts.length; ++i) {
+            var singleNodeSet = contexts[i];
+            var rhs = this.val(ast[2], singleNodeSet);
+            var success;
+            if ('number' === typeof rhs) {
+              success = rhs === singleNodeSet.pos[0][0];
+            } else {
+              success = fn['boolean'](rhs);
+            }
+            if (success) {
+              var node = singleNodeSet.nodes[0];
+              ret.nodes.push(node);
+              // skip over all the rest of the same node.
+              while (i+1 < contexts.length && node === contexts[i+1].nodes[0]) {
+                i++;
+              }
+            }
+          }
+          return ret;
+        case 'PathExpr':
+          // turn the path into an expressoin; i.e., remove the position
+          // information of the last axis.
+          var x = this.val(ast[1], ctx);
+          // Make the nodeset a forward-direction-only one.
+          if (x.finalize) {  // it is a NodeMultiSet
+            return {nodes: x.nodes};
+          } else {
+            return x;
+          }
+        case '/':
+          // TODO: don't generate '/' nodes, just Axis nodes.
+          var lhs = this.val(ast[1], ctx);
+          console.assert(null != lhs);
+          var r = this.val(ast[2], lhs);
+          console.assert(null != r);
+          return r;
+        case 'Axis':
+          // All the axis tests from Step. We only get AxisSpecifier NodeTest,
+          // not the predicate (which is applied later)
+          var axis = ast[1],
+              nodeType = ast[2],
+              nodeTypeNum = nodeTypes[nodeType],
+              shouldLowerCase = true,  // TODO: give option
+              nodeName = ast[3] && shouldLowerCase ? ast[3].toLowerCase() : ast[3];
+          nodeName = nodeName === '*' ? null : nodeName;
+          if ('object' !== typeof ctx) return {nodes:[], pos:[]};
+          var nodeList = ctx.nodes.slice();  // TODO: is copy needed?
+          var r = axes[axis](nodeList  /*destructive!*/, nodeTypeNum, nodeName, shouldLowerCase);
+          return r;
+      }
+    }
+  };
+  var evaluate = xpath.evaluate = function evaluate(expr, doc, context) {
+    //var astFactory = new AstEvaluatorFactory(doc, context);
+    var stream = new Stream(expr);
+    var ast = parse(stream, astFactory);
+    var val = new Evaluator(doc).val(ast, {nodes: [context]});
+    return val;
+  }
+
+  /***************************************************************************
+   *                           DOM interface                                 *
+   ***************************************************************************/
+  var XPathException = xpath.XPathException = function XPathException(code, message) {
+    var e = new Error(message);
+    e.name = 'XPathException';
+    e.code = code;
+    return e;
+  }
+  XPathException.INVALID_EXPRESSION_ERR = 51;
+  XPathException.TYPE_ERR = 52;
+
+
+  var XPathEvaluator = xpath.XPathEvaluator = function XPathEvaluator() {}
+  XPathEvaluator.prototype = {
+    createExpression: function(expression, resolver) {
+      return new XPathExpression(expression, resolver);
+    },
+    createNSResolver: function(nodeResolver) {
+      // TODO
+    },
+    evaluate: function evaluate(expression, contextNode, resolver, type, result) {
+      var expr = new XPathExpression(expression, resolver);
+      return expr.evaluate(contextNode, type, result);
+    }
+  };
+
+
+  var XPathExpression = xpath.XPathExpression = function XPathExpression(expression, resolver, optDoc) {
+    var stream = new Stream(expression);
+    this._ast = parse(stream, astFactory);
+    this._doc = optDoc;
+  }
+  XPathExpression.prototype = {
+    evaluate: function evaluate(contextNode, type, result) {
+      if (null == contextNode.nodeType)
+        throw new Error('bad argument (expected context node): ' + contextNode);
+      var doc = contextNode.ownerDocument || contextNode;
+      if (null != this._doc && this._doc !== doc) {
+        throw new core.DOMException(
+            core.DOMException.WRONG_DOCUMENT_ERR,
+            'The document must be the same as the context node\'s document.');
+      }
+      var evaluator = new Evaluator(doc);
+      var value = evaluator.val(this._ast, {nodes: [contextNode]});
+      if (XPathResult.NUMBER_TYPE === type)
+        value = fn.number(value);
+      else if (XPathResult.STRING_TYPE === type)
+        value = fn.string(value);
+      else if (XPathResult.BOOLEAN_TYPE === type)
+        value = fn['boolean'](value);
+      else if (XPathResult.ANY_TYPE !== type &&
+               XPathResult.UNORDERED_NODE_ITERATOR_TYPE !== type &&
+               XPathResult.ORDERED_NODE_ITERATOR_TYPE !== type &&
+               XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE !== type &&
+               XPathResult.ORDERED_NODE_SNAPSHOT_TYPE !== type &&
+               XPathResult.ANY_UNORDERED_NODE_TYPE !== type &&
+               XPathResult.FIRST_ORDERED_NODE_TYPE !== type)
+        throw new core.DOMException(
+            core.DOMException.NOT_SUPPORTED_ERR,
+            'You must provide an XPath result type (0=any).');
+      else if (XPathResult.ANY_TYPE !== type &&
+               'object' !== typeof value)
+        throw new XPathException(
+            XPathException.TYPE_ERR,
+            'Value should be a node-set: ' + value);
+      return new XPathResult(doc, value, type);
+    }
+  }
+
+  var XPathResult = xpath.XPathResult = function XPathResult(doc, value, resultType) {
+    this._value = value;
+    this._resultType = resultType;
+    this._i = 0;
+
+    // TODO: we removed mutation events but didn't take care of this. No tests fail, so that's nice, but eventually we
+    // should fix this, preferably by entirely replacing our XPath implementation.
+    // this._invalidated = false;
+    // if (this.resultType === XPathResult.UNORDERED_NODE_ITERATOR_TYPE ||
+    //     this.resultType === XPathResult.ORDERED_NODE_ITERATOR_TYPE) {
+    //   doc.addEventListener('DOMSubtreeModified', invalidate, true);
+    //   var self = this;
+    //   function invalidate() {
+    //     self._invalidated = true;
+    //     doc.removeEventListener('DOMSubtreeModified', invalidate, true);
+    //   }
+    // }
+  }
+  XPathResult.ANY_TYPE = 0;
+  XPathResult.NUMBER_TYPE = 1;
+  XPathResult.STRING_TYPE = 2;
+  XPathResult.BOOLEAN_TYPE = 3;
+  XPathResult.UNORDERED_NODE_ITERATOR_TYPE = 4;
+  XPathResult.ORDERED_NODE_ITERATOR_TYPE = 5;
+  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE = 6;
+  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7;
+  XPathResult.ANY_UNORDERED_NODE_TYPE = 8;
+  XPathResult.FIRST_ORDERED_NODE_TYPE = 9;
+  var proto = {
+    // XPathResultType
+    get resultType() {
+      if (this._resultType) return this._resultType;
+      switch (typeof this._value) {
+        case 'number': return XPathResult.NUMBER_TYPE;
+        case 'string': return XPathResult.STRING_TYPE;
+        case 'boolean': return XPathResult.BOOLEAN_TYPE;
+        default: return XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
+      }
+    },
+    get numberValue() {
+      if (XPathResult.NUMBER_TYPE !== this.resultType)
+        throw new XPathException(XPathException.TYPE_ERR,
+                                 'You should have asked for a NUMBER_TYPE.');
+      return this._value;
+    },
+    get stringValue() {
+      if (XPathResult.STRING_TYPE !== this.resultType)
+        throw new XPathException(XPathException.TYPE_ERR,
+                                 'You should have asked for a STRING_TYPE.');
+      return this._value;
+    },
+    get booleanValue() {
+      if (XPathResult.BOOLEAN_TYPE !== this.resultType)
+        throw new XPathException(XPathException.TYPE_ERR,
+                                 'You should have asked for a BOOLEAN_TYPE.');
+      return this._value;
+    },
+    get singleNodeValue() {
+      if (XPathResult.ANY_UNORDERED_NODE_TYPE !== this.resultType &&
+          XPathResult.FIRST_ORDERED_NODE_TYPE !== this.resultType)
+        throw new XPathException(
+            XPathException.TYPE_ERR,
+            'You should have asked for a FIRST_ORDERED_NODE_TYPE.');
+      return this._value.nodes[0] || null;
+    },
+    get invalidIteratorState() {
+      if (XPathResult.UNORDERED_NODE_ITERATOR_TYPE !== this.resultType &&
+          XPathResult.ORDERED_NODE_ITERATOR_TYPE !== this.resultType)
+        return false;
+      return !!this._invalidated;
+    },
+    get snapshotLength() {
+      if (XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE !== this.resultType &&
+          XPathResult.ORDERED_NODE_SNAPSHOT_TYPE !== this.resultType)
+        throw new XPathException(
+            XPathException.TYPE_ERR,
+            'You should have asked for a ORDERED_NODE_SNAPSHOT_TYPE.');
+      return this._value.nodes.length;
+    },
+    iterateNext: function iterateNext() {
+      if (XPathResult.UNORDERED_NODE_ITERATOR_TYPE !== this.resultType &&
+          XPathResult.ORDERED_NODE_ITERATOR_TYPE !== this.resultType)
+        throw new XPathException(
+            XPathException.TYPE_ERR,
+            'You should have asked for a ORDERED_NODE_ITERATOR_TYPE.');
+      if (this.invalidIteratorState)
+        throw new core.DOMException(
+            core.DOMException.INVALID_STATE_ERR,
+            'The document has been mutated since the result was returned');
+      return this._value.nodes[this._i++] || null;
+    },
+    snapshotItem: function snapshotItem(index) {
+      if (XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE !== this.resultType &&
+          XPathResult.ORDERED_NODE_SNAPSHOT_TYPE !== this.resultType)
+        throw new XPathException(
+            XPathException.TYPE_ERR,
+            'You should have asked for a ORDERED_NODE_SNAPSHOT_TYPE.');
+      return this._value.nodes[index] || null;
+    }
+  };
+  // so you can access ANY_TYPE etc. from the instances:
+  XPathResult.prototype = Object.create(XPathResult,
+      Object.keys(proto).reduce(function (descriptors, name) {
+        descriptors[name] = Object.getOwnPropertyDescriptor(proto, name);
+        return descriptors;
+      }, {
+        constructor: {
+          value: XPathResult,
+          writable: true,
+          configurable: true
+        }
+      }));
+
+  core.XPathException = XPathException;
+  core.XPathExpression = XPathExpression;
+  core.XPathResult = XPathResult;
+  core.XPathEvaluator = XPathEvaluator;
+
+  core.Document.prototype.createExpression =
+    XPathEvaluator.prototype.createExpression;
+
+  core.Document.prototype.createNSResolver =
+      XPathEvaluator.prototype.createNSResolver;
+
+  core.Document.prototype.evaluate = XPathEvaluator.prototype.evaluate;
+
+  return xpath; // for tests
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/aborting/AbortController-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/aborting/AbortController-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/aborting/AbortController-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+
+const AbortSignal = require("../generated/AbortSignal");
+
+class AbortControllerImpl {
+  constructor(globalObject) {
+    this.signal = AbortSignal.createImpl(globalObject, []);
+  }
+
+  abort() {
+    this.signal._signalAbort();
+  }
+}
+
+module.exports = {
+  implementation: AbortControllerImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/aborting/AbortSignal-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/aborting/AbortSignal-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/aborting/AbortSignal-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+"use strict";
+
+const { setupForSimpleEventAccessors } = require("../helpers/create-event-accessor");
+const { fireAnEvent } = require("../helpers/events");
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+const AbortSignal = require("../generated/AbortSignal");
+
+class AbortSignalImpl extends EventTargetImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    // make event firing possible
+    this._ownerDocument = globalObject.document;
+
+    this.aborted = false;
+    this.abortAlgorithms = new Set();
+  }
+
+  static abort(globalObject) {
+    const abortSignal = AbortSignal.createImpl(globalObject, []);
+    abortSignal.aborted = true;
+    return abortSignal;
+  }
+
+  _signalAbort() {
+    if (this.aborted) {
+      return;
+    }
+    this.aborted = true;
+
+    for (const algorithm of this.abortAlgorithms) {
+      algorithm();
+    }
+    this.abortAlgorithms.clear();
+
+    fireAnEvent("abort", this);
+  }
+
+  _addAlgorithm(algorithm) {
+    if (this.aborted) {
+      return;
+    }
+    this.abortAlgorithms.add(algorithm);
+  }
+
+  _removeAlgorithm(algorithm) {
+    this.abortAlgorithms.delete(algorithm);
+  }
+}
+
+setupForSimpleEventAccessors(AbortSignalImpl.prototype, ["abort"]);
+
+module.exports = {
+  implementation: AbortSignalImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/attributes.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/attributes.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/attributes.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,312 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const { HTML_NS } = require("./helpers/namespaces");
+const { asciiLowercase } = require("./helpers/strings");
+const { queueAttributeMutationRecord } = require("./helpers/mutation-observers");
+const { enqueueCECallbackReaction } = require("./helpers/custom-elements");
+
+// The following three are for https://dom.spec.whatwg.org/#concept-element-attribute-has. We don't just have a
+// predicate tester since removing that kind of flexibility gives us the potential for better future optimizations.
+
+/* eslint-disable no-restricted-properties */
+
+exports.hasAttribute = function (element, A) {
+  return element._attributeList.includes(A);
+};
+
+exports.hasAttributeByName = function (element, name) {
+  return element._attributesByNameMap.has(name);
+};
+
+exports.hasAttributeByNameNS = function (element, namespace, localName) {
+  return element._attributeList.some(attribute => {
+    return attribute._localName === localName && attribute._namespace === namespace;
+  });
+};
+
+// https://dom.spec.whatwg.org/#concept-element-attributes-change
+exports.changeAttribute = (element, attribute, value) => {
+  const { _localName, _namespace, _value } = attribute;
+
+  queueAttributeMutationRecord(element, _localName, _namespace, _value);
+
+  if (element._ceState === "custom") {
+    enqueueCECallbackReaction(element, "attributeChangedCallback", [
+      _localName,
+      _value,
+      value,
+      _namespace
+    ]);
+  }
+
+  attribute._value = value;
+
+  // Run jsdom hooks; roughly correspond to spec's "An attribute is set and an attribute is changed."
+  element._attrModified(attribute._qualifiedName, value, _value);
+};
+
+// https://dom.spec.whatwg.org/#concept-element-attributes-append
+exports.appendAttribute = function (element, attribute) {
+  const { _localName, _namespace, _value } = attribute;
+  queueAttributeMutationRecord(element, _localName, _namespace, null);
+
+  if (element._ceState === "custom") {
+    enqueueCECallbackReaction(element, "attributeChangedCallback", [
+      _localName,
+      null,
+      _value,
+      _namespace
+    ]);
+  }
+
+  const attributeList = element._attributeList;
+
+  attributeList.push(attribute);
+  attribute._element = element;
+
+  // Sync name cache
+  const name = attribute._qualifiedName;
+  const cache = element._attributesByNameMap;
+  let entry = cache.get(name);
+  if (!entry) {
+    entry = [];
+    cache.set(name, entry);
+  }
+  entry.push(attribute);
+
+  // Run jsdom hooks; roughly correspond to spec's "An attribute is set and an attribute is added."
+  element._attrModified(name, _value, null);
+};
+
+exports.removeAttribute = function (element, attribute) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-remove
+
+  const { _localName, _namespace, _value } = attribute;
+
+  queueAttributeMutationRecord(element, _localName, _namespace, _value);
+
+  if (element._ceState === "custom") {
+    enqueueCECallbackReaction(element, "attributeChangedCallback", [
+      _localName,
+      _value,
+      null,
+      _namespace
+    ]);
+  }
+
+  const attributeList = element._attributeList;
+
+  for (let i = 0; i < attributeList.length; ++i) {
+    if (attributeList[i] === attribute) {
+      attributeList.splice(i, 1);
+      attribute._element = null;
+
+      // Sync name cache
+      const name = attribute._qualifiedName;
+      const cache = element._attributesByNameMap;
+      const entry = cache.get(name);
+      entry.splice(entry.indexOf(attribute), 1);
+      if (entry.length === 0) {
+        cache.delete(name);
+      }
+
+      // Run jsdom hooks; roughly correspond to spec's "An attribute is removed."
+      element._attrModified(name, null, attribute._value);
+
+      return;
+    }
+  }
+};
+
+exports.replaceAttribute = function (element, oldAttr, newAttr) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-replace
+
+  const { _localName, _namespace, _value } = oldAttr;
+
+  queueAttributeMutationRecord(element, _localName, _namespace, _value);
+
+  if (element._ceState === "custom") {
+    enqueueCECallbackReaction(element, "attributeChangedCallback", [
+      _localName,
+      _value,
+      newAttr._value,
+      _namespace
+    ]);
+  }
+
+  const attributeList = element._attributeList;
+
+  for (let i = 0; i < attributeList.length; ++i) {
+    if (attributeList[i] === oldAttr) {
+      attributeList.splice(i, 1, newAttr);
+      oldAttr._element = null;
+      newAttr._element = element;
+
+      // Sync name cache
+      const name = newAttr._qualifiedName;
+      const cache = element._attributesByNameMap;
+      let entry = cache.get(name);
+      if (!entry) {
+        entry = [];
+        cache.set(name, entry);
+      }
+      entry.splice(entry.indexOf(oldAttr), 1, newAttr);
+
+      // Run jsdom hooks; roughly correspond to spec's "An attribute is set and an attribute is changed."
+      element._attrModified(name, newAttr._value, oldAttr._value);
+
+      return;
+    }
+  }
+};
+
+exports.getAttributeByName = function (element, name) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
+
+  if (element._namespaceURI === HTML_NS &&
+      element._ownerDocument._parsingMode === "html") {
+    name = asciiLowercase(name);
+  }
+
+  const cache = element._attributesByNameMap;
+  const entry = cache.get(name);
+  if (!entry) {
+    return null;
+  }
+
+  return entry[0];
+};
+
+exports.getAttributeByNameNS = function (element, namespace, localName) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-get-by-namespace
+
+  if (namespace === "") {
+    namespace = null;
+  }
+
+  const attributeList = element._attributeList;
+  for (let i = 0; i < attributeList.length; ++i) {
+    const attr = attributeList[i];
+    if (attr._namespace === namespace && attr._localName === localName) {
+      return attr;
+    }
+  }
+
+  return null;
+};
+
+// Both of the following functions implement https://dom.spec.whatwg.org/#concept-element-attributes-get-value.
+// Separated them into two to keep symmetry with other functions.
+exports.getAttributeValue = function (element, localName) {
+  const attr = exports.getAttributeByNameNS(element, null, localName);
+
+  if (!attr) {
+    return "";
+  }
+
+  return attr._value;
+};
+
+exports.getAttributeValueNS = function (element, namespace, localName) {
+  const attr = exports.getAttributeByNameNS(element, namespace, localName);
+
+  if (!attr) {
+    return "";
+  }
+
+  return attr._value;
+};
+
+exports.setAttribute = function (element, attr) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-set
+
+  if (attr._element !== null && attr._element !== element) {
+    throw DOMException.create(element._globalObject, ["The attribute is in use.", "InUseAttributeError"]);
+  }
+
+  const oldAttr = exports.getAttributeByNameNS(element, attr._namespace, attr._localName);
+  if (oldAttr === attr) {
+    return attr;
+  }
+
+  if (oldAttr !== null) {
+    exports.replaceAttribute(element, oldAttr, attr);
+  } else {
+    exports.appendAttribute(element, attr);
+  }
+
+  return oldAttr;
+};
+
+exports.setAttributeValue = function (element, localName, value, prefix, namespace) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-set-value
+
+  if (prefix === undefined) {
+    prefix = null;
+  }
+  if (namespace === undefined) {
+    namespace = null;
+  }
+
+  const attribute = exports.getAttributeByNameNS(element, namespace, localName);
+  if (attribute === null) {
+    const newAttribute = element._ownerDocument._createAttribute({
+      namespace,
+      namespacePrefix: prefix,
+      localName,
+      value
+    });
+    exports.appendAttribute(element, newAttribute);
+
+    return;
+  }
+
+  exports.changeAttribute(element, attribute, value);
+};
+
+// https://dom.spec.whatwg.org/#set-an-existing-attribute-value
+exports.setAnExistingAttributeValue = (attribute, value) => {
+  const element = attribute._element;
+  if (element === null) {
+    attribute._value = value;
+  } else {
+    exports.changeAttribute(element, attribute, value);
+  }
+};
+
+exports.removeAttributeByName = function (element, name) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-name
+
+  const attr = exports.getAttributeByName(element, name);
+
+  if (attr !== null) {
+    exports.removeAttribute(element, attr);
+  }
+
+  return attr;
+};
+
+exports.removeAttributeByNameNS = function (element, namespace, localName) {
+  // https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-namespace
+
+  const attr = exports.getAttributeByNameNS(element, namespace, localName);
+
+  if (attr !== null) {
+    exports.removeAttribute(element, attr);
+  }
+
+  return attr;
+};
+
+exports.attributeNames = function (element) {
+  // Needed by https://dom.spec.whatwg.org/#dom-element-getattributenames
+
+  return element._attributeList.map(a => a._qualifiedName);
+};
+
+exports.hasAttributes = function (element) {
+  // Needed by https://dom.spec.whatwg.org/#dom-element-hasattributes
+
+  return element._attributeList.length > 0;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/attributes/Attr-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/attributes/Attr-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/attributes/Attr-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,60 @@
+"use strict";
+
+const { setAnExistingAttributeValue } = require("../attributes.js");
+const NodeImpl = require("../nodes/Node-impl.js").implementation;
+const { ATTRIBUTE_NODE } = require("../node-type.js");
+
+exports.implementation = class AttrImpl extends NodeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._namespace = privateData.namespace !== undefined ? privateData.namespace : null;
+    this._namespacePrefix = privateData.namespacePrefix !== undefined ? privateData.namespacePrefix : null;
+    this._localName = privateData.localName;
+    this._value = privateData.value !== undefined ? privateData.value : "";
+    this._element = privateData.element !== undefined ? privateData.element : null;
+
+    this.nodeType = ATTRIBUTE_NODE;
+    this.specified = true;
+  }
+
+  get namespaceURI() {
+    return this._namespace;
+  }
+
+  get prefix() {
+    return this._namespacePrefix;
+  }
+
+  get localName() {
+    return this._localName;
+  }
+
+  get name() {
+    return this._qualifiedName;
+  }
+
+  get nodeName() {
+    return this._qualifiedName;
+  }
+
+  get value() {
+    return this._value;
+  }
+  set value(value) {
+    setAnExistingAttributeValue(this, value);
+  }
+
+  get ownerElement() {
+    return this._element;
+  }
+
+  get _qualifiedName() {
+    // https://dom.spec.whatwg.org/#concept-attribute-qualified-name
+    if (this._namespacePrefix === null) {
+      return this._localName;
+    }
+
+    return this._namespacePrefix + ":" + this._localName;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/attributes/NamedNodeMap-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/attributes/NamedNodeMap-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/attributes/NamedNodeMap-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,78 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const idlUtils = require("../generated/utils.js");
+const attributes = require("../attributes.js");
+const { HTML_NS } = require("../helpers/namespaces");
+
+exports.implementation = class NamedNodeMapImpl {
+  constructor(globalObject, args, privateData) {
+    this._element = privateData.element;
+
+    this._globalObject = globalObject;
+  }
+  get _attributeList() {
+    return this._element._attributeList;
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    return this._attributeList.keys();
+  }
+  get length() {
+    return this._attributeList.length;
+  }
+  item(index) {
+    if (index >= this._attributeList.length) {
+      return null;
+    }
+    return this._attributeList[index];
+  }
+
+  get [idlUtils.supportedPropertyNames]() {
+    const names = new Set(this._attributeList.map(a => a._qualifiedName));
+    const el = this._element;
+    if (el._namespaceURI === HTML_NS && el._ownerDocument._parsingMode === "html") {
+      for (const name of names) {
+        const lowercaseName = name.toLowerCase();
+        if (lowercaseName !== name) {
+          names.delete(name);
+        }
+      }
+    }
+    return names;
+  }
+  getNamedItem(qualifiedName) {
+    return attributes.getAttributeByName(this._element, qualifiedName);
+  }
+  getNamedItemNS(namespace, localName) {
+    return attributes.getAttributeByNameNS(this._element, namespace, localName);
+  }
+  setNamedItem(attr) {
+    // eslint-disable-next-line no-restricted-properties
+    return attributes.setAttribute(this._element, attr);
+  }
+  setNamedItemNS(attr) {
+    // eslint-disable-next-line no-restricted-properties
+    return attributes.setAttribute(this._element, attr);
+  }
+  removeNamedItem(qualifiedName) {
+    const attr = attributes.removeAttributeByName(this._element, qualifiedName);
+    if (attr === null) {
+      throw DOMException.create(this._globalObject, [
+        "Tried to remove an attribute that was not present",
+        "NotFoundError"
+      ]);
+    }
+    return attr;
+  }
+  removeNamedItemNS(namespace, localName) {
+    const attr = attributes.removeAttributeByNameNS(this._element, namespace, localName);
+    if (attr === null) {
+      throw DOMException.create(this._globalObject, [
+        "Tried to remove an attribute that was not present",
+        "NotFoundError"
+      ]);
+    }
+    return attr;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/constraint-validation/DefaultConstraintValidation-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/constraint-validation/DefaultConstraintValidation-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/constraint-validation/DefaultConstraintValidation-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,75 @@
+"use strict";
+
+const ValidityState = require("../generated/ValidityState");
+const { isDisabled } = require("../helpers/form-controls");
+const { closest } = require("../helpers/traversal");
+const { fireAnEvent } = require("../helpers/events");
+
+exports.implementation = class DefaultConstraintValidationImpl {
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-willvalidate
+  get willValidate() {
+    return this._isCandidateForConstraintValidation();
+  }
+
+  get validity() {
+    if (!this._validity) {
+      this._validity = ValidityState.createImpl(this._globalObject, [], {
+        element: this
+      });
+    }
+    return this._validity;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-checkvalidity
+  checkValidity() {
+    if (!this._isCandidateForConstraintValidation()) {
+      return true;
+    }
+    if (this._satisfiesConstraints()) {
+      return true;
+    }
+    fireAnEvent("invalid", this, undefined, { cancelable: true });
+    return false;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-setcustomvalidity
+  setCustomValidity(message) {
+    this._customValidityErrorMessage = message;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-reportvalidity
+  // Since jsdom has no user interaction, it's the same as #checkValidity
+  reportValidity() {
+    return this.checkValidity();
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-cva-validationmessage
+  get validationMessage() {
+    const { validity } = this;
+    if (!this._isCandidateForConstraintValidation() || this._satisfiesConstraints()) {
+      return "";
+    }
+    const isSufferingFromCustomError = validity.customError;
+    if (isSufferingFromCustomError) {
+      return this._customValidityErrorMessage;
+    }
+    return "Constraints not satisfied";
+  }
+
+  _isCandidateForConstraintValidation() {
+    // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
+    return !isDisabled(this) &&
+      // If an element has a datalist element ancestor,
+      // it is barred from constraint validation.
+      closest(this, "datalist") === null &&
+      !this._barredFromConstraintValidationSpecialization();
+  }
+
+  _isBarredFromConstraintValidation() {
+    return !this._isCandidateForConstraintValidation();
+  }
+
+  _satisfiesConstraints() {
+    return this.validity.valid;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/constraint-validation/ValidityState-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/constraint-validation/ValidityState-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/constraint-validation/ValidityState-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,66 @@
+"use strict";
+
+exports.implementation = class ValidityStateImpl {
+  constructor(globalObject, args, privateData) {
+    const { element, state = {} } = privateData;
+
+    this._element = element;
+    this._state = state;
+  }
+
+  get badInput() {
+    return this._failsConstraint("badInput");
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-custom-error
+  get customError() {
+    return this._element._customValidityErrorMessage !== "";
+  }
+
+  get patternMismatch() {
+    return this._failsConstraint("patternMismatch");
+  }
+
+  get rangeOverflow() {
+    return this._failsConstraint("rangeOverflow");
+  }
+
+  get rangeUnderflow() {
+    return this._failsConstraint("rangeUnderflow");
+  }
+
+  get stepMismatch() {
+    return this._failsConstraint("stepMismatch");
+  }
+
+  get tooLong() {
+    return this._failsConstraint("tooLong");
+  }
+
+  get tooShort() {
+    return this._failsConstraint("tooShort");
+  }
+
+  get typeMismatch() {
+    return this._failsConstraint("typeMismatch");
+  }
+
+  get valueMissing() {
+    return this._failsConstraint("valueMissing");
+  }
+
+  _failsConstraint(method) {
+    const validationMethod = this._state[method];
+    if (validationMethod) {
+      return validationMethod();
+    }
+
+    return false;
+  }
+
+  get valid() {
+    return !(this.badInput || this.valueMissing || this.customError ||
+            this.patternMismatch || this.rangeOverflow || this.rangeUnderflow ||
+            this.stepMismatch || this.tooLong || this.tooShort || this.typeMismatch);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/cssom/StyleSheetList-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/cssom/StyleSheetList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/cssom/StyleSheetList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+
+exports.implementation = class StyleSheetList {
+  constructor() {
+    this._list = [];
+  }
+
+  get length() {
+    return this._list.length;
+  }
+
+  item(index) {
+    const result = this._list[index];
+    return result !== undefined ? result : null;
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    return this._list.keys();
+  }
+
+  _add(sheet) {
+    const { _list } = this;
+    if (!_list.includes(sheet)) {
+      _list.push(sheet);
+    }
+  }
+
+  _remove(sheet) {
+    const { _list } = this;
+
+    const index = _list.indexOf(sheet);
+    if (index >= 0) {
+      _list.splice(index, 1);
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/custom-elements/CustomElementRegistry-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/custom-elements/CustomElementRegistry-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/custom-elements/CustomElementRegistry-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,265 @@
+"use strict";
+
+const webIDLConversions = require("webidl-conversions");
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const NODE_TYPE = require("../node-type");
+
+const { HTML_NS } = require("../helpers/namespaces");
+const { getHTMLElementInterface } = require("../helpers/create-element");
+const { shadowIncludingInclusiveDescendantsIterator } = require("../helpers/shadow-dom");
+const { isValidCustomElementName, tryUpgradeElement, enqueueCEUpgradeReaction } = require("../helpers/custom-elements");
+
+const idlUtils = require("../generated/utils");
+const IDLFunction = require("../generated/Function.js");
+const HTMLUnknownElement = require("../generated/HTMLUnknownElement");
+
+const LIFECYCLE_CALLBACKS = [
+  "connectedCallback",
+  "disconnectedCallback",
+  "adoptedCallback",
+  "attributeChangedCallback"
+];
+
+function convertToSequenceDOMString(obj) {
+  if (!obj || !obj[Symbol.iterator]) {
+    throw new TypeError("Invalid Sequence");
+  }
+
+  return Array.from(obj).map(webIDLConversions.DOMString);
+}
+
+// Returns true is the passed value is a valid constructor.
+// Borrowed from: https://stackoverflow.com/a/39336206/3832710
+function isConstructor(value) {
+  if (typeof value !== "function") {
+    return false;
+  }
+
+  try {
+    const P = new Proxy(value, {
+      construct() {
+        return {};
+      }
+    });
+
+    // eslint-disable-next-line no-new
+    new P();
+
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+// https://html.spec.whatwg.org/#customelementregistry
+class CustomElementRegistryImpl {
+  constructor(globalObject) {
+    this._customElementDefinitions = [];
+    this._elementDefinitionIsRunning = false;
+    this._whenDefinedPromiseMap = Object.create(null);
+
+    this._globalObject = globalObject;
+  }
+
+  // https://html.spec.whatwg.org/#dom-customelementregistry-define
+  define(name, constructor, options) {
+    const { _globalObject } = this;
+    const ctor = constructor.objectReference;
+
+    if (!isConstructor(ctor)) {
+      throw new TypeError("Constructor argument is not a constructor.");
+    }
+
+    if (!isValidCustomElementName(name)) {
+      throw DOMException.create(_globalObject, ["Name argument is not a valid custom element name.", "SyntaxError"]);
+    }
+
+    const nameAlreadyRegistered = this._customElementDefinitions.some(entry => entry.name === name);
+    if (nameAlreadyRegistered) {
+      throw DOMException.create(_globalObject, [
+        "This name has already been registered in the registry.",
+        "NotSupportedError"
+      ]);
+    }
+
+    const ctorAlreadyRegistered = this._customElementDefinitions.some(entry => entry.objectReference === ctor);
+    if (ctorAlreadyRegistered) {
+      throw DOMException.create(_globalObject, [
+        "This constructor has already been registered in the registry.",
+        "NotSupportedError"
+      ]);
+    }
+
+    let localName = name;
+
+    let extendsOption = null;
+    if (options !== undefined && options.extends) {
+      extendsOption = options.extends;
+    }
+
+    if (extendsOption !== null) {
+      if (isValidCustomElementName(extendsOption)) {
+        throw DOMException.create(_globalObject, [
+          "Option extends value can't be a valid custom element name.",
+          "NotSupportedError"
+        ]);
+      }
+
+      const extendsInterface = getHTMLElementInterface(extendsOption);
+      if (extendsInterface === HTMLUnknownElement) {
+        throw DOMException.create(_globalObject, [
+          `${extendsOption} is an HTMLUnknownElement.`,
+          "NotSupportedError"
+        ]);
+      }
+
+      localName = extendsOption;
+    }
+
+    if (this._elementDefinitionIsRunning) {
+      throw DOMException.create(_globalObject, [
+        "Invalid nested custom element definition.",
+        "NotSupportedError"
+      ]);
+    }
+
+    this._elementDefinitionIsRunning = true;
+
+    let disableShadow = false;
+    let observedAttributes = [];
+    const lifecycleCallbacks = {
+      connectedCallback: null,
+      disconnectedCallback: null,
+      adoptedCallback: null,
+      attributeChangedCallback: null
+    };
+
+    let caughtError;
+    try {
+      const { prototype } = ctor;
+
+      if (typeof prototype !== "object") {
+        throw new TypeError("Invalid constructor prototype.");
+      }
+
+      for (const callbackName of LIFECYCLE_CALLBACKS) {
+        const callbackValue = prototype[callbackName];
+
+        if (callbackValue !== undefined) {
+          lifecycleCallbacks[callbackName] = IDLFunction.convert(callbackValue, {
+            context: `The lifecycle callback "${callbackName}"`
+          });
+        }
+      }
+
+      if (lifecycleCallbacks.attributeChangedCallback !== null) {
+        const observedAttributesIterable = ctor.observedAttributes;
+
+        if (observedAttributesIterable !== undefined) {
+          observedAttributes = convertToSequenceDOMString(observedAttributesIterable);
+        }
+      }
+
+      let disabledFeatures = [];
+      const disabledFeaturesIterable = ctor.disabledFeatures;
+      if (disabledFeaturesIterable) {
+        disabledFeatures = convertToSequenceDOMString(disabledFeaturesIterable);
+      }
+
+      disableShadow = disabledFeatures.includes("shadow");
+    } catch (err) {
+      caughtError = err;
+    } finally {
+      this._elementDefinitionIsRunning = false;
+    }
+
+    if (caughtError !== undefined) {
+      throw caughtError;
+    }
+
+    const definition = {
+      name,
+      localName,
+      constructor,
+      objectReference: ctor,
+      observedAttributes,
+      lifecycleCallbacks,
+      disableShadow,
+      constructionStack: []
+    };
+
+    this._customElementDefinitions.push(definition);
+
+    const document = idlUtils.implForWrapper(this._globalObject._document);
+
+    const upgradeCandidates = [];
+    for (const candidate of shadowIncludingInclusiveDescendantsIterator(document)) {
+      if (
+        (candidate._namespaceURI === HTML_NS && candidate._localName === localName) &&
+        (extendsOption === null || candidate._isValue === name)
+      ) {
+        upgradeCandidates.push(candidate);
+      }
+    }
+
+    for (const upgradeCandidate of upgradeCandidates) {
+      enqueueCEUpgradeReaction(upgradeCandidate, definition);
+    }
+
+    if (this._whenDefinedPromiseMap[name] !== undefined) {
+      this._whenDefinedPromiseMap[name].resolve(ctor);
+      delete this._whenDefinedPromiseMap[name];
+    }
+  }
+
+  // https://html.spec.whatwg.org/#dom-customelementregistry-get
+  get(name) {
+    const definition = this._customElementDefinitions.find(entry => entry.name === name);
+    return definition && definition.objectReference;
+  }
+
+  // https://html.spec.whatwg.org/#dom-customelementregistry-whendefined
+  whenDefined(name) {
+    if (!isValidCustomElementName(name)) {
+      return Promise.reject(DOMException.create(
+        this._globalObject,
+        ["Name argument is not a valid custom element name.", "SyntaxError"]
+      ));
+    }
+
+    const alreadyRegistered = this._customElementDefinitions.find(entry => entry.name === name);
+    if (alreadyRegistered) {
+      return Promise.resolve(alreadyRegistered.objectReference);
+    }
+
+    if (this._whenDefinedPromiseMap[name] === undefined) {
+      let resolve;
+      const promise = new Promise(r => {
+        resolve = r;
+      });
+
+      // Store the pending Promise along with the extracted resolve callback to actually resolve the returned Promise,
+      // once the custom element is registered.
+      this._whenDefinedPromiseMap[name] = {
+        promise,
+        resolve
+      };
+    }
+
+    return this._whenDefinedPromiseMap[name].promise;
+  }
+
+  // https://html.spec.whatwg.org/#dom-customelementregistry-upgrade
+  upgrade(root) {
+    for (const candidate of shadowIncludingInclusiveDescendantsIterator(root)) {
+      if (candidate.nodeType === NODE_TYPE.ELEMENT_NODE) {
+        tryUpgradeElement(candidate);
+      }
+    }
+  }
+}
+
+module.exports = {
+  implementation: CustomElementRegistryImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/documents.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/documents.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/documents.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+const XMLDocument = require("../living/generated/XMLDocument.js");
+const Document = require("../living/generated/Document.js");
+const { wrapperForImpl } = require("./generated/utils.js");
+
+exports.createImpl = (globalObject, options, { alwaysUseDocumentClass = false } = {}) => {
+  if (options.parsingMode === "xml" && !alwaysUseDocumentClass) {
+    return XMLDocument.createImpl(globalObject, [], { options });
+  }
+  return Document.createImpl(globalObject, [], { options });
+};
+
+exports.createWrapper = (...args) => {
+  return wrapperForImpl(exports.createImpl(...args));
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/domparsing/DOMParser-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/domparsing/DOMParser-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/domparsing/DOMParser-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,58 @@
+"use strict";
+
+const { parseIntoDocument } = require("../../browser/parser");
+
+const Document = require("../generated/Document");
+
+exports.implementation = class DOMParserImpl {
+  constructor(globalObject) {
+    this._globalObject = globalObject;
+  }
+
+  parseFromString(string, contentType) {
+    switch (String(contentType)) {
+      case "text/html": {
+        return this.createScriptingDisabledDocument("html", contentType, string);
+      }
+
+      case "text/xml":
+      case "application/xml":
+      case "application/xhtml+xml":
+      case "image/svg+xml": {
+        try {
+          return this.createScriptingDisabledDocument("xml", contentType, string);
+        } catch (error) {
+          const document = this.createScriptingDisabledDocument("xml", contentType);
+          const element = document.createElementNS("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror");
+
+          element.textContent = error.message;
+
+          document.appendChild(element);
+          return document;
+        }
+      }
+
+      default:
+        throw new TypeError("Invalid contentType");
+    }
+  }
+
+  createScriptingDisabledDocument(parsingMode, contentType, string) {
+    const document = Document.createImpl(this._globalObject, [], {
+      options: {
+        parsingMode,
+        encoding: "UTF-8",
+        contentType,
+        readyState: "complete",
+        scriptingDisabled: true
+        // TODO: somehow set URL to active document's URL
+      }
+    });
+
+    if (string !== undefined) {
+      parseIntoDocument(string, document);
+    }
+
+    return document;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/domparsing/InnerHTML-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/domparsing/InnerHTML-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/domparsing/InnerHTML-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+"use strict";
+
+const { parseFragment } = require("../../browser/parser");
+const { HTML_NS } = require("../helpers/namespaces.js");
+const { isShadowRoot } = require("../helpers/shadow-dom.js");
+const NODE_TYPE = require("../node-type.js");
+const { fragmentSerialization } = require("./serialization.js");
+
+// https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin
+exports.implementation = class InnerHTMLImpl {
+  // https://w3c.github.io/DOM-Parsing/#dom-innerhtml-innerhtml
+  get innerHTML() {
+    return fragmentSerialization(this, {
+      requireWellFormed: true,
+      globalObject: this._globalObject
+    });
+  }
+  set innerHTML(markup) {
+    const contextElement = isShadowRoot(this) ? this.host : this;
+    const fragment = parseFragment(markup, contextElement);
+
+    let contextObject = this;
+    if (this.nodeType === NODE_TYPE.ELEMENT_NODE && this.localName === "template" && this.namespaceURI === HTML_NS) {
+      contextObject = this._templateContents;
+    }
+
+    contextObject._replaceAll(fragment);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/domparsing/XMLSerializer-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/domparsing/XMLSerializer-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/domparsing/XMLSerializer-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+"use strict";
+const serialize = require("w3c-xmlserializer");
+const DOMException = require("domexception/webidl2js-wrapper");
+const utils = require("../generated/utils");
+
+exports.implementation = class XMLSerializerImpl {
+  constructor(globalObject) {
+    this._globalObject = globalObject;
+  }
+
+  serializeToString(root) {
+    try {
+      return serialize(utils.wrapperForImpl(root), { requireWellFormed: false });
+    } catch (e) {
+      throw DOMException.create(this._globalObject, [e.message, "InvalidStateError"]);
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/domparsing/parse5-adapter-serialization.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/domparsing/parse5-adapter-serialization.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/domparsing/parse5-adapter-serialization.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,63 @@
+"use strict";
+const nodeTypes = require("../node-type");
+const { domSymbolTree } = require("../helpers/internal-constants");
+// Serialization only requires a subset of the tree adapter interface.
+
+// Tree traversing
+exports.getFirstChild = node => node.firstChild;
+
+exports.getChildNodes = node => node.childNodesForSerializing || domSymbolTree.childrenToArray(node);
+
+exports.getParentNode = node => node.parentNode;
+
+exports.getAttrList = element => {
+  const attributeList = [...element._attributeList];
+
+  if (element._isValue && attributeList.every(attr => attr.name !== "is")) {
+    attributeList.unshift({
+      name: "is",
+      namespace: null,
+      prefix: null,
+      value: element._isValue
+    });
+  }
+
+  return attributeList;
+};
+
+// Node data
+exports.getTagName = element => element._qualifiedName; // https://github.com/inikulin/parse5/issues/231
+
+exports.getNamespaceURI = element => element.namespaceURI;
+
+exports.getTextNodeContent = exports.getCommentNodeContent = node => node.data;
+
+exports.getDocumentTypeNodeName = node => node.name;
+
+exports.getDocumentTypeNodePublicId = node => node.publicId;
+
+exports.getDocumentTypeNodeSystemId = node => node.systemId;
+
+exports.getTemplateContent = templateElement => templateElement._templateContents;
+
+exports.getDocumentMode = document => document._mode;
+
+// Node types
+exports.isTextNode = node => node.nodeType === nodeTypes.TEXT_NODE;
+
+exports.isCommentNode = node => node.nodeType === nodeTypes.COMMENT_NODE;
+
+exports.isDocumentTypeNode = node => node.nodeType === nodeTypes.DOCUMENT_TYPE_NODE;
+
+exports.isElementNode = node => node.nodeType === nodeTypes.ELEMENT_NODE;
+
+// Source code location
+exports.setNodeSourceCodeLocation = (node, location) => {
+  node.sourceCodeLocation = location;
+};
+
+exports.getNodeSourceCodeLocation = node => node.sourceCodeLocation;
+
+exports.updateNodeSourceCodeLocation = (node, endLocation) => {
+  Object.assign(node.sourceCodeLocation, endLocation);
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/domparsing/serialization.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/domparsing/serialization.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/domparsing/serialization.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,45 @@
+"use strict";
+
+const produceXMLSerialization = require("w3c-xmlserializer");
+const parse5 = require("parse5");
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const utils = require("../generated/utils");
+const treeAdapter = require("./parse5-adapter-serialization");
+const NODE_TYPE = require("../node-type");
+const NAMESPACES = require("../helpers/namespaces");
+
+function htmlSerialization(node) {
+  if (
+    node.nodeType === NODE_TYPE.ELEMENT_NODE &&
+    node.namespaceURI === NAMESPACES.HTML_NS &&
+    node.tagName === "TEMPLATE"
+  ) {
+    node = node.content;
+  }
+
+  return parse5.serialize(node, { treeAdapter });
+}
+
+module.exports.fragmentSerialization = (node, { requireWellFormed, globalObject }) => {
+  const contextDocument =
+    node.nodeType === NODE_TYPE.DOCUMENT_NODE ? node : node._ownerDocument;
+  if (contextDocument._parsingMode === "html") {
+    return htmlSerialization(node);
+  }
+
+  const childNodes = node.childNodesForSerializing || node.childNodes;
+
+  try {
+    let serialized = "";
+    for (let i = 0; i < childNodes.length; ++i) {
+      serialized += produceXMLSerialization(
+        utils.wrapperForImpl(childNodes[i] || childNodes.item(i)),
+        { requireWellFormed }
+      );
+    }
+    return serialized;
+  } catch (e) {
+    throw DOMException.create(globalObject, [e.message, "InvalidStateError"]);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/CloseEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/CloseEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/CloseEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,10 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const CloseEventInit = require("../generated/CloseEventInit");
+
+class CloseEventImpl extends EventImpl {}
+CloseEventImpl.defaultInit = CloseEventInit.convert(undefined);
+
+exports.implementation = CloseEventImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/CompositionEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/CompositionEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/CompositionEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+"use strict";
+
+const UIEventImpl = require("./UIEvent-impl").implementation;
+const CompositionEventInit = require("../generated/CompositionEventInit");
+
+class CompositionEventImpl extends UIEventImpl {
+  initCompositionEvent(type, bubbles, cancelable, view, data) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initUIEvent(type, bubbles, cancelable, view, 0);
+    this.data = data;
+  }
+}
+CompositionEventImpl.defaultInit = CompositionEventInit.convert(undefined);
+
+module.exports = {
+  implementation: CompositionEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/CustomEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/CustomEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/CustomEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const CustomEventInit = require("../generated/CustomEventInit");
+
+class CustomEventImpl extends EventImpl {
+  initCustomEvent(type, bubbles, cancelable, detail) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initEvent(type, bubbles, cancelable);
+    this.detail = detail;
+  }
+}
+CustomEventImpl.defaultInit = CustomEventInit.convert(undefined);
+
+module.exports = {
+  implementation: CustomEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/ErrorEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/ErrorEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/ErrorEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const ErrorEventInit = require("../generated/ErrorEventInit");
+
+class ErrorEventImpl extends EventImpl {
+
+}
+ErrorEventImpl.defaultInit = ErrorEventInit.convert(undefined);
+
+module.exports = {
+  implementation: ErrorEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/Event-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/Event-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/Event-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,197 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const EventInit = require("../generated/EventInit");
+
+class EventImpl {
+  constructor(globalObject, args, privateData) {
+    const [type, eventInitDict = this.constructor.defaultInit] = args;
+
+    this.type = type;
+
+    this.bubbles = false;
+    this.cancelable = false;
+    for (const key in eventInitDict) {
+      if (key in this.constructor.defaultInit) {
+        this[key] = eventInitDict[key];
+      }
+    }
+    for (const key in this.constructor.defaultInit) {
+      if (!(key in this)) {
+        this[key] = this.constructor.defaultInit[key];
+      }
+    }
+
+    this.target = null;
+    this.currentTarget = null;
+    this.eventPhase = 0;
+
+    this._globalObject = globalObject;
+    this._initializedFlag = true;
+    this._stopPropagationFlag = false;
+    this._stopImmediatePropagationFlag = false;
+    this._canceledFlag = false;
+    this._inPassiveListenerFlag = false;
+    this._dispatchFlag = false;
+    this._path = [];
+
+    this.isTrusted = privateData.isTrusted || false;
+    this.timeStamp = Date.now();
+  }
+
+  // https://dom.spec.whatwg.org/#set-the-canceled-flag
+  _setTheCanceledFlag() {
+    if (this.cancelable && !this._inPassiveListenerFlag) {
+      this._canceledFlag = true;
+    }
+  }
+
+  get srcElement() {
+    return this.target;
+  }
+
+  get returnValue() {
+    return !this._canceledFlag;
+  }
+
+  set returnValue(v) {
+    if (v === false) {
+      this._setTheCanceledFlag();
+    }
+  }
+
+  get defaultPrevented() {
+    return this._canceledFlag;
+  }
+
+  stopPropagation() {
+    this._stopPropagationFlag = true;
+  }
+
+  get cancelBubble() {
+    return this._stopPropagationFlag;
+  }
+
+  set cancelBubble(v) {
+    if (v) {
+      this._stopPropagationFlag = true;
+    }
+  }
+
+  stopImmediatePropagation() {
+    this._stopPropagationFlag = true;
+    this._stopImmediatePropagationFlag = true;
+  }
+
+  preventDefault() {
+    this._setTheCanceledFlag();
+  }
+
+  // https://dom.spec.whatwg.org/#dom-event-composedpath
+  // Current implementation is based of https://whatpr.org/dom/699.html#dom-event-composedpath
+  // due to a bug in composed path implementation https://github.com/whatwg/dom/issues/684
+  composedPath() {
+    const composedPath = [];
+
+    const { currentTarget, _path: path } = this;
+
+    if (path.length === 0) {
+      return composedPath;
+    }
+
+    composedPath.push(currentTarget);
+
+    let currentTargetIndex = 0;
+    let currentTargetHiddenSubtreeLevel = 0;
+
+    for (let index = path.length - 1; index >= 0; index--) {
+      const { item, rootOfClosedTree, slotInClosedTree } = path[index];
+
+      if (rootOfClosedTree) {
+        currentTargetHiddenSubtreeLevel++;
+      }
+
+      if (item === idlUtils.implForWrapper(currentTarget)) {
+        currentTargetIndex = index;
+        break;
+      }
+
+      if (slotInClosedTree) {
+        currentTargetHiddenSubtreeLevel--;
+      }
+    }
+
+    let currentHiddenLevel = currentTargetHiddenSubtreeLevel;
+    let maxHiddenLevel = currentTargetHiddenSubtreeLevel;
+
+    for (let i = currentTargetIndex - 1; i >= 0; i--) {
+      const { item, rootOfClosedTree, slotInClosedTree } = path[i];
+
+      if (rootOfClosedTree) {
+        currentHiddenLevel++;
+      }
+
+      if (currentHiddenLevel <= maxHiddenLevel) {
+        composedPath.unshift(idlUtils.wrapperForImpl(item));
+      }
+
+      if (slotInClosedTree) {
+        currentHiddenLevel--;
+        if (currentHiddenLevel < maxHiddenLevel) {
+          maxHiddenLevel = currentHiddenLevel;
+        }
+      }
+    }
+
+    currentHiddenLevel = currentTargetHiddenSubtreeLevel;
+    maxHiddenLevel = currentTargetHiddenSubtreeLevel;
+
+    for (let index = currentTargetIndex + 1; index < path.length; index++) {
+      const { item, rootOfClosedTree, slotInClosedTree } = path[index];
+
+      if (slotInClosedTree) {
+        currentHiddenLevel++;
+      }
+
+      if (currentHiddenLevel <= maxHiddenLevel) {
+        composedPath.push(idlUtils.wrapperForImpl(item));
+      }
+
+      if (rootOfClosedTree) {
+        currentHiddenLevel--;
+        if (currentHiddenLevel < maxHiddenLevel) {
+          maxHiddenLevel = currentHiddenLevel;
+        }
+      }
+    }
+
+    return composedPath;
+  }
+
+  _initialize(type, bubbles, cancelable) {
+    this.type = type;
+    this._initializedFlag = true;
+
+    this._stopPropagationFlag = false;
+    this._stopImmediatePropagationFlag = false;
+    this._canceledFlag = false;
+
+    this.isTrusted = false;
+    this.target = null;
+    this.bubbles = bubbles;
+    this.cancelable = cancelable;
+  }
+
+  initEvent(type, bubbles, cancelable) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this._initialize(type, bubbles, cancelable);
+  }
+}
+EventImpl.defaultInit = EventInit.convert(undefined);
+
+module.exports = {
+  implementation: EventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/EventModifierMixin-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/EventModifierMixin-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/EventModifierMixin-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+"use strict";
+
+// This mixin doesn't have an IDL equivalent, but since MouseEvent and KeyboardEvent implement getModifierState() the
+// same way, its implementation is shared here.
+
+class EventModifierMixinImpl {
+  // Event's constructor assumes all options correspond to IDL attributes with the same names, and sets them on `this`.
+  // That is not the case for these modifier boolean options, but since the options are set on `this` anyway we'll
+  // access them that way. The spec doesn't say much about the case where keyArg is not one of the valid ones
+  // (https://w3c.github.io/uievents-key/#keys-modifier), but at least Chrome returns false for invalid modifiers. Since
+  // these invalid modifiers will be undefined on `this` (thus `false` after casting it to boolean), we don't need to do
+  // extra checking for validity.
+  getModifierState(keyArg) {
+    return Boolean(this[`modifier${keyArg}`]);
+  }
+}
+
+exports.implementation = EventModifierMixinImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,403 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const reportException = require("../helpers/runtime-script-errors");
+const idlUtils = require("../generated/utils");
+const { nodeRoot } = require("../helpers/node");
+const {
+  isNode, isShadowRoot, isSlotable, getEventTargetParent,
+  isShadowInclusiveAncestor, retarget
+} = require("../helpers/shadow-dom");
+
+const MouseEvent = require("../generated/MouseEvent");
+
+const EVENT_PHASE = {
+  NONE: 0,
+  CAPTURING_PHASE: 1,
+  AT_TARGET: 2,
+  BUBBLING_PHASE: 3
+};
+
+class EventTargetImpl {
+  constructor(globalObject) {
+    this._globalObject = globalObject;
+    this._eventListeners = Object.create(null);
+  }
+
+  addEventListener(type, callback, options) {
+    options = normalizeEventHandlerOptions(options, ["capture", "once", "passive"]);
+
+    if (callback === null) {
+      return;
+    }
+
+    if (!this._eventListeners[type]) {
+      this._eventListeners[type] = [];
+    }
+
+    for (let i = 0; i < this._eventListeners[type].length; ++i) {
+      const listener = this._eventListeners[type][i];
+      if (
+        listener.callback.objectReference === callback.objectReference &&
+        listener.options.capture === options.capture
+      ) {
+        return;
+      }
+    }
+
+    this._eventListeners[type].push({
+      callback,
+      options
+    });
+  }
+
+  removeEventListener(type, callback, options) {
+    options = normalizeEventHandlerOptions(options, ["capture"]);
+
+    if (callback === null) {
+      // Optimization, not in the spec.
+      return;
+    }
+
+    if (!this._eventListeners[type]) {
+      return;
+    }
+
+    for (let i = 0; i < this._eventListeners[type].length; ++i) {
+      const listener = this._eventListeners[type][i];
+      if (
+        listener.callback.objectReference === callback.objectReference &&
+        listener.options.capture === options.capture
+      ) {
+        this._eventListeners[type].splice(i, 1);
+        break;
+      }
+    }
+  }
+
+  dispatchEvent(eventImpl) {
+    if (eventImpl._dispatchFlag || !eventImpl._initializedFlag) {
+      throw DOMException.create(this._globalObject, [
+        "Tried to dispatch an uninitialized event",
+        "InvalidStateError"
+      ]);
+    }
+    if (eventImpl.eventPhase !== EVENT_PHASE.NONE) {
+      throw DOMException.create(this._globalObject, [
+        "Tried to dispatch a dispatching event",
+        "InvalidStateError"
+      ]);
+    }
+
+    eventImpl.isTrusted = false;
+
+    return this._dispatch(eventImpl);
+  }
+
+  // https://dom.spec.whatwg.org/#get-the-parent
+  _getTheParent() {
+    return null;
+  }
+
+  // https://dom.spec.whatwg.org/#concept-event-dispatch
+  // legacyOutputDidListenersThrowFlag optional parameter is not necessary here since it is only used by indexDB.
+  _dispatch(eventImpl, targetOverride /* , legacyOutputDidListenersThrowFlag */) {
+    let targetImpl = this;
+    let clearTargets = false;
+    let activationTarget = null;
+
+    eventImpl._dispatchFlag = true;
+
+    targetOverride = targetOverride || targetImpl;
+    let relatedTarget = retarget(eventImpl.relatedTarget, targetImpl);
+
+    if (targetImpl !== relatedTarget || targetImpl === eventImpl.relatedTarget) {
+      const touchTargets = [];
+
+      appendToEventPath(eventImpl, targetImpl, targetOverride, relatedTarget, touchTargets, false);
+
+      const isActivationEvent = MouseEvent.isImpl(eventImpl) && eventImpl.type === "click";
+
+      if (isActivationEvent && targetImpl._hasActivationBehavior) {
+        activationTarget = targetImpl;
+      }
+
+      let slotInClosedTree = false;
+      let slotable = isSlotable(targetImpl) && targetImpl._assignedSlot ? targetImpl : null;
+      let parent = getEventTargetParent(targetImpl, eventImpl);
+
+      // Populate event path
+      // https://dom.spec.whatwg.org/#event-path
+      while (parent !== null) {
+        if (slotable !== null) {
+          if (parent.localName !== "slot") {
+            throw new Error(`JSDOM Internal Error: Expected parent to be a Slot`);
+          }
+
+          slotable = null;
+
+          const parentRoot = nodeRoot(parent);
+          if (isShadowRoot(parentRoot) && parentRoot.mode === "closed") {
+            slotInClosedTree = true;
+          }
+        }
+
+        if (isSlotable(parent) && parent._assignedSlot) {
+          slotable = parent;
+        }
+
+        relatedTarget = retarget(eventImpl.relatedTarget, parent);
+
+        if (
+          (isNode(parent) && isShadowInclusiveAncestor(nodeRoot(targetImpl), parent)) ||
+          idlUtils.wrapperForImpl(parent).constructor.name === "Window"
+        ) {
+          if (isActivationEvent && eventImpl.bubbles && activationTarget === null &&
+              parent._hasActivationBehavior) {
+            activationTarget = parent;
+          }
+
+          appendToEventPath(eventImpl, parent, null, relatedTarget, touchTargets, slotInClosedTree);
+        } else if (parent === relatedTarget) {
+          parent = null;
+        } else {
+          targetImpl = parent;
+
+          if (isActivationEvent && activationTarget === null && targetImpl._hasActivationBehavior) {
+            activationTarget = targetImpl;
+          }
+
+          appendToEventPath(eventImpl, parent, targetImpl, relatedTarget, touchTargets, slotInClosedTree);
+        }
+
+        if (parent !== null) {
+          parent = getEventTargetParent(parent, eventImpl);
+        }
+
+        slotInClosedTree = false;
+      }
+
+      let clearTargetsStructIndex = -1;
+      for (let i = eventImpl._path.length - 1; i >= 0 && clearTargetsStructIndex === -1; i--) {
+        if (eventImpl._path[i].target !== null) {
+          clearTargetsStructIndex = i;
+        }
+      }
+      const clearTargetsStruct = eventImpl._path[clearTargetsStructIndex];
+
+      clearTargets =
+          (isNode(clearTargetsStruct.target) && isShadowRoot(nodeRoot(clearTargetsStruct.target))) ||
+          (isNode(clearTargetsStruct.relatedTarget) && isShadowRoot(nodeRoot(clearTargetsStruct.relatedTarget)));
+
+      if (activationTarget !== null && activationTarget._legacyPreActivationBehavior) {
+        activationTarget._legacyPreActivationBehavior();
+      }
+
+      for (let i = eventImpl._path.length - 1; i >= 0; --i) {
+        const struct = eventImpl._path[i];
+
+        if (struct.target !== null) {
+          eventImpl.eventPhase = EVENT_PHASE.AT_TARGET;
+        } else {
+          eventImpl.eventPhase = EVENT_PHASE.CAPTURING_PHASE;
+        }
+
+        invokeEventListeners(struct, eventImpl, "capturing");
+      }
+
+      for (let i = 0; i < eventImpl._path.length; i++) {
+        const struct = eventImpl._path[i];
+
+        if (struct.target !== null) {
+          eventImpl.eventPhase = EVENT_PHASE.AT_TARGET;
+        } else {
+          if (!eventImpl.bubbles) {
+            continue;
+          }
+
+          eventImpl.eventPhase = EVENT_PHASE.BUBBLING_PHASE;
+        }
+
+        invokeEventListeners(struct, eventImpl, "bubbling");
+      }
+    }
+
+    eventImpl.eventPhase = EVENT_PHASE.NONE;
+
+    eventImpl.currentTarget = null;
+    eventImpl._path = [];
+    eventImpl._dispatchFlag = false;
+    eventImpl._stopPropagationFlag = false;
+    eventImpl._stopImmediatePropagationFlag = false;
+
+    if (clearTargets) {
+      eventImpl.target = null;
+      eventImpl.relatedTarget = null;
+    }
+
+    if (activationTarget !== null) {
+      if (!eventImpl._canceledFlag) {
+        activationTarget._activationBehavior(eventImpl);
+      } else if (activationTarget._legacyCanceledActivationBehavior) {
+        activationTarget._legacyCanceledActivationBehavior();
+      }
+    }
+
+    return !eventImpl._canceledFlag;
+  }
+}
+
+module.exports = {
+  implementation: EventTargetImpl
+};
+
+// https://dom.spec.whatwg.org/#concept-event-listener-invoke
+function invokeEventListeners(struct, eventImpl, phase) {
+  const structIndex = eventImpl._path.indexOf(struct);
+  for (let i = structIndex; i >= 0; i--) {
+    const t = eventImpl._path[i];
+    if (t.target) {
+      eventImpl.target = t.target;
+      break;
+    }
+  }
+
+  eventImpl.relatedTarget = idlUtils.wrapperForImpl(struct.relatedTarget);
+
+  if (eventImpl._stopPropagationFlag) {
+    return;
+  }
+
+  eventImpl.currentTarget = idlUtils.wrapperForImpl(struct.item);
+
+  const listeners = struct.item._eventListeners;
+  innerInvokeEventListeners(eventImpl, listeners, phase, struct.itemInShadowTree);
+}
+
+// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
+function innerInvokeEventListeners(eventImpl, listeners, phase, itemInShadowTree) {
+  let found = false;
+
+  const { type, target } = eventImpl;
+  const wrapper = idlUtils.wrapperForImpl(target);
+
+  if (!listeners || !listeners[type]) {
+    return found;
+  }
+
+  // Copy event listeners before iterating since the list can be modified during the iteration.
+  const handlers = listeners[type].slice();
+
+  for (let i = 0; i < handlers.length; i++) {
+    const listener = handlers[i];
+    const { capture, once, passive } = listener.options;
+
+    // Check if the event listener has been removed since the listeners has been cloned.
+    if (!listeners[type].includes(listener)) {
+      continue;
+    }
+
+    found = true;
+
+    if (
+      (phase === "capturing" && !capture) ||
+      (phase === "bubbling" && capture)
+    ) {
+      continue;
+    }
+
+    if (once) {
+      listeners[type].splice(listeners[type].indexOf(listener), 1);
+    }
+
+    let window = null;
+    if (wrapper && wrapper._document) {
+      // Triggered by Window
+      window = wrapper;
+    } else if (target._ownerDocument) {
+      // Triggered by most webidl2js'ed instances
+      window = target._ownerDocument._defaultView;
+    } else if (wrapper._ownerDocument) {
+      // Currently triggered by some non-webidl2js things
+      window = wrapper._ownerDocument._defaultView;
+    }
+
+    let currentEvent;
+    if (window) {
+      currentEvent = window._currentEvent;
+      if (!itemInShadowTree) {
+        window._currentEvent = eventImpl;
+      }
+    }
+
+    if (passive) {
+      eventImpl._inPassiveListenerFlag = true;
+    }
+
+    try {
+      listener.callback.call(eventImpl.currentTarget, eventImpl);
+    } catch (e) {
+      if (window) {
+        reportException(window, e);
+      }
+      // Errors in window-less documents just get swallowed... can you think of anything better?
+    }
+
+    eventImpl._inPassiveListenerFlag = false;
+
+    if (window) {
+      window._currentEvent = currentEvent;
+    }
+
+    if (eventImpl._stopImmediatePropagationFlag) {
+      return found;
+    }
+  }
+
+  return found;
+}
+
+/**
+ * Normalize the event listeners options argument in order to get always a valid options object
+ * @param   {Object} options         - user defined options
+ * @param   {Array} defaultBoolKeys  - boolean properties that should belong to the options object
+ * @returns {Object} object containing at least the "defaultBoolKeys"
+ */
+function normalizeEventHandlerOptions(options, defaultBoolKeys) {
+  const returnValue = {};
+
+  // no need to go further here
+  if (typeof options === "boolean" || options === null || typeof options === "undefined") {
+    returnValue.capture = Boolean(options);
+    return returnValue;
+  }
+
+  // non objects options so we typecast its value as "capture" value
+  if (typeof options !== "object") {
+    returnValue.capture = Boolean(options);
+    // at this point we don't need to loop the "capture" key anymore
+    defaultBoolKeys = defaultBoolKeys.filter(k => k !== "capture");
+  }
+
+  for (const key of defaultBoolKeys) {
+    returnValue[key] = Boolean(options[key]);
+  }
+
+  return returnValue;
+}
+
+// https://dom.spec.whatwg.org/#concept-event-path-append
+function appendToEventPath(eventImpl, target, targetOverride, relatedTarget, touchTargets, slotInClosedTree) {
+  const itemInShadowTree = isNode(target) && isShadowRoot(nodeRoot(target));
+  const rootOfClosedTree = isShadowRoot(target) && target.mode === "closed";
+
+  eventImpl._path.push({
+    item: target,
+    itemInShadowTree,
+    target: targetOverride,
+    relatedTarget,
+    touchTargets,
+    rootOfClosedTree,
+    slotInClosedTree
+  });
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/FocusEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/FocusEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/FocusEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+const UIEventImpl = require("./UIEvent-impl").implementation;
+
+const FocusEventInit = require("../generated/FocusEventInit");
+
+class FocusEventImpl extends UIEventImpl {}
+FocusEventImpl.defaultInit = FocusEventInit.convert(undefined);
+
+exports.implementation = FocusEventImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/HashChangeEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/HashChangeEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/HashChangeEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const HashChangeEventInit = require("../generated/HashChangeEventInit");
+
+class HashChangeEventImpl extends EventImpl {
+
+}
+HashChangeEventImpl.defaultInit = HashChangeEventInit.convert(undefined);
+
+module.exports = {
+  implementation: HashChangeEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/InputEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/InputEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/InputEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,11 @@
+"use strict";
+const UIEventImpl = require("./UIEvent-impl").implementation;
+const InputEventInit = require("../generated/InputEventInit");
+
+// https://w3c.github.io/uievents/#interface-inputevent
+class InputEventImpl extends UIEventImpl { }
+InputEventImpl.defaultInit = InputEventInit.convert(undefined);
+
+module.exports = {
+  implementation: InputEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/KeyboardEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/KeyboardEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/KeyboardEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const EventModifierMixinImpl = require("./EventModifierMixin-impl").implementation;
+const UIEventImpl = require("./UIEvent-impl").implementation;
+
+const KeyboardEventInit = require("../generated/KeyboardEventInit");
+
+class KeyboardEventImpl extends UIEventImpl {
+  initKeyboardEvent(type, bubbles, cancelable, view, key, location, ctrlKey, altKey, shiftKey, metaKey) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initUIEvent(type, bubbles, cancelable, view, 0);
+    this.key = key;
+    this.location = location;
+    this.ctrlKey = ctrlKey;
+    this.altKey = altKey;
+    this.shiftKey = shiftKey;
+    this.metaKey = metaKey;
+  }
+}
+mixin(KeyboardEventImpl.prototype, EventModifierMixinImpl.prototype);
+KeyboardEventImpl.defaultInit = KeyboardEventInit.convert(undefined);
+
+module.exports = {
+  implementation: KeyboardEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/MessageEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/MessageEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/MessageEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const MessageEventInit = require("../generated/MessageEventInit");
+
+class MessageEventImpl extends EventImpl {
+  initMessageEvent(type, bubbles, cancelable, data, origin, lastEventId, source, ports) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initEvent(type, bubbles, cancelable);
+    this.data = data;
+    this.origin = origin;
+    this.lastEventId = lastEventId;
+    this.source = source;
+    this.ports = ports;
+  }
+}
+MessageEventImpl.defaultInit = MessageEventInit.convert(undefined);
+
+module.exports = {
+  implementation: MessageEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/MouseEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/MouseEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/MouseEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,49 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const EventModifierMixinImpl = require("./EventModifierMixin-impl").implementation;
+const UIEventImpl = require("./UIEvent-impl").implementation;
+
+const MouseEventInit = require("../generated/MouseEventInit");
+
+class MouseEventImpl extends UIEventImpl {
+  initMouseEvent(
+    type,
+    bubbles,
+    cancelable,
+    view,
+    detail,
+    screenX,
+    screenY,
+    clientX,
+    clientY,
+    ctrlKey,
+    altKey,
+    shiftKey,
+    metaKey,
+    button,
+    relatedTarget
+  ) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initUIEvent(type, bubbles, cancelable, view, detail);
+    this.screenX = screenX;
+    this.screenY = screenY;
+    this.clientX = clientX;
+    this.clientY = clientY;
+    this.ctrlKey = ctrlKey;
+    this.altKey = altKey;
+    this.shiftKey = shiftKey;
+    this.metaKey = metaKey;
+    this.button = button;
+    this.relatedTarget = relatedTarget;
+  }
+}
+mixin(MouseEventImpl.prototype, EventModifierMixinImpl.prototype);
+MouseEventImpl.defaultInit = MouseEventInit.convert(undefined);
+
+module.exports = {
+  implementation: MouseEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/PageTransitionEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/PageTransitionEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/PageTransitionEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const PageTransitionEventInit = require("../generated/PageTransitionEventInit");
+
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#pagetransitionevent
+class PageTransitionEventImpl extends EventImpl {
+  initPageTransitionEvent(type, bubbles, cancelable, persisted) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initEvent(type, bubbles, cancelable);
+    this.persisted = persisted;
+  }
+}
+PageTransitionEventImpl.defaultInit = PageTransitionEventInit.convert(undefined);
+
+exports.implementation = PageTransitionEventImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/PopStateEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/PopStateEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/PopStateEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+const EventImpl = require("./Event-impl.js").implementation;
+
+const PopStateEventInit = require("../generated/PopStateEventInit");
+
+class PopStateEventImpl extends EventImpl {}
+PopStateEventImpl.defaultInit = PopStateEventInit.convert(undefined);
+
+exports.implementation = PopStateEventImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/ProgressEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/ProgressEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/ProgressEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const ProgressEventInit = require("../generated/ProgressEventInit");
+
+class ProgressEventImpl extends EventImpl {
+
+}
+ProgressEventImpl.defaultInit = ProgressEventInit.convert(undefined);
+
+module.exports = {
+  implementation: ProgressEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/StorageEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/StorageEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/StorageEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+"use strict";
+
+const EventImpl = require("./Event-impl").implementation;
+
+const StorageEventInit = require("../generated/StorageEventInit");
+
+// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
+class StorageEventImpl extends EventImpl {
+  initStorageEvent(type, bubbles, cancelable, key, oldValue, newValue, url, storageArea) {
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initEvent(type, bubbles, cancelable);
+    this.key = key;
+    this.oldValue = oldValue;
+    this.newValue = newValue;
+    this.url = url;
+    this.storageArea = storageArea;
+  }
+}
+StorageEventImpl.defaultInit = StorageEventInit.convert(undefined);
+
+module.exports = {
+  implementation: StorageEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/TouchEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/TouchEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/TouchEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,14 @@
+"use strict";
+
+const UIEventImpl = require("./UIEvent-impl").implementation;
+
+const TouchEventInit = require("../generated/TouchEventInit");
+
+class TouchEventImpl extends UIEventImpl {
+
+}
+TouchEventImpl.defaultInit = TouchEventInit.convert(undefined);
+
+module.exports = {
+  implementation: TouchEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/UIEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/UIEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/UIEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const UIEventInit = require("../generated/UIEventInit");
+const EventImpl = require("./Event-impl").implementation;
+
+// Until webidl2js gains support for checking for Window, this would have to do.
+function isWindow(val) {
+  if (typeof val !== "object") {
+    return false;
+  }
+  const wrapper = idlUtils.wrapperForImpl(val);
+  if (typeof wrapper === "object") {
+    return wrapper === wrapper._globalProxy;
+  }
+
+  // `val` may be either impl or wrapper currently, because webidl2js currently unwraps Window objects (and their global
+  // proxies) to their underlying EventTargetImpl during conversion, which is not what we want. But at the same time,
+  // some internal usage call this constructor with the actual global proxy.
+  return isWindow(idlUtils.implForWrapper(val));
+}
+
+class UIEventImpl extends EventImpl {
+  constructor(globalObject, args, privateData) {
+    const eventInitDict = args[1];
+
+    // undefined check included so that we can omit the property in internal usage.
+    if (eventInitDict && eventInitDict.view !== null && eventInitDict.view !== undefined) {
+      if (!isWindow(eventInitDict.view)) {
+        throw new TypeError(`Failed to construct '${new.target.name.replace(/Impl$/, "")}': member view is not of ` +
+                            "type Window.");
+      }
+    }
+
+    super(globalObject, args, privateData);
+  }
+
+  initUIEvent(type, bubbles, cancelable, view, detail) {
+    if (view !== null) {
+      if (!isWindow(view)) {
+        throw new TypeError(`Failed to execute 'initUIEvent' on '${this.constructor.name.replace(/Impl$/, "")}': ` +
+                            "parameter 4 is not of type 'Window'.");
+      }
+    }
+
+    if (this._dispatchFlag) {
+      return;
+    }
+
+    this.initEvent(type, bubbles, cancelable);
+    this.view = view;
+    this.detail = detail;
+  }
+}
+UIEventImpl.defaultInit = UIEventInit.convert(undefined);
+
+module.exports = {
+  implementation: UIEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/events/WheelEvent-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/events/WheelEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/events/WheelEvent-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const MouseEventImpl = require("./MouseEvent-impl").implementation;
+
+const WheelEventInit = require("../generated/WheelEventInit");
+
+class WheelEventImpl extends MouseEventImpl {}
+WheelEventImpl.defaultInit = WheelEventInit.convert(undefined);
+
+module.exports = {
+  implementation: WheelEventImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/fetch/Headers-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/fetch/Headers-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/fetch/Headers-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,165 @@
+"use strict";
+
+const {
+  isForbidden,
+  isForbiddenResponse,
+  isPrivilegedNoCORSRequest,
+  isNoCORSSafelistedRequest,
+  isCORSWhitelisted
+} = require("./header-types");
+const HeaderList = require("./header-list");
+
+function assertName(name) {
+  if (!name.match(/^[!#$%&'*+\-.^`|~\w]+$/)) {
+    throw new TypeError("name is invalid");
+  }
+}
+
+function assertValue(value) {
+  if (value.match(/[\0\r\n]/)) {
+    throw new TypeError("value is invalid");
+  }
+}
+
+class HeadersImpl {
+  constructor(globalObject, args) {
+    this.guard = "none";
+    this.headersList = new HeaderList();
+
+    if (args[0]) {
+      this._fill(args[0]);
+    }
+  }
+
+  _fill(init) {
+    if (Array.isArray(init)) {
+      for (const header of init) {
+        if (header.length !== 2) {
+          throw new TypeError("init is invalid");
+        }
+        this.append(header[0], header[1]);
+      }
+    } else {
+      for (const key of Object.keys(init)) {
+        this.append(key, init[key]);
+      }
+    }
+  }
+
+  has(name) {
+    assertName(name);
+    return this.headersList.contains(name);
+  }
+
+  get(name) {
+    assertName(name);
+    return this.headersList.get(name);
+  }
+
+  _removePrivilegedNoCORSHeaders() {
+    this.headersList.delete("range");
+  }
+
+  append(name, value) {
+    value = value.trim();
+    assertName(name);
+    assertValue(value);
+
+    switch (this.guard) {
+      case "immutable":
+        throw new TypeError("Headers is immutable");
+      case "request":
+        if (isForbidden(name)) {
+          return;
+        }
+        break;
+      case "request-no-cors": {
+        let temporaryValue = this.get(name);
+        if (temporaryValue === null) {
+          temporaryValue = value;
+        } else {
+          temporaryValue += `, ${value}`;
+        }
+        if (!isCORSWhitelisted(name, value)) {
+          return;
+        }
+        break;
+      }
+      case "response":
+        if (isForbiddenResponse(name)) {
+          return;
+        }
+        break;
+    }
+
+    this.headersList.append(name, value);
+    this._removePrivilegedNoCORSHeaders();
+  }
+
+  set(name, value) {
+    value = value.trim();
+    assertName(name);
+    assertValue(value);
+
+    switch (this.guard) {
+      case "immutable":
+        throw new TypeError("Headers is immutable");
+      case "request":
+        if (isForbidden(name)) {
+          return;
+        }
+        break;
+      case "request-no-cors": {
+        if (!isCORSWhitelisted(name, value)) {
+          return;
+        }
+        break;
+      }
+      case "response":
+        if (isForbiddenResponse(name)) {
+          return;
+        }
+        break;
+    }
+    this.headersList.set(name, value);
+    this._removePrivilegedNoCORSHeaders();
+  }
+
+  delete(name) {
+    assertName(name);
+
+    switch (this.guard) {
+      case "immutable":
+        throw new TypeError("Headers is immutable");
+      case "request":
+        if (isForbidden(name)) {
+          return;
+        }
+        break;
+      case "request-no-cors": {
+        if (
+          !isNoCORSSafelistedRequest(name) &&
+          !isPrivilegedNoCORSRequest(name)
+        ) {
+          return;
+        }
+        break;
+      }
+      case "response":
+        if (isForbiddenResponse(name)) {
+          return;
+        }
+        break;
+    }
+    this.headersList.delete(name);
+    this._removePrivilegedNoCORSHeaders();
+  }
+
+  * [Symbol.iterator]() {
+    for (const header of this.headersList.sortAndCombine()) {
+      yield header;
+    }
+  }
+}
+
+exports.implementation = HeadersImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/fetch/header-list.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/fetch/header-list.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/fetch/header-list.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+"use strict";
+
+/**
+ * Provides some utility functions for somewhat efficiently modifying a
+ * collection of headers.
+ *
+ * Note that this class only operates on ByteStrings (which is also why we use
+ * toLowerCase internally).
+ */
+class HeaderList {
+  constructor() {
+    this.headers = new Map();
+  }
+
+  append(name, value) {
+    const existing = this.headers.get(name.toLowerCase());
+    if (existing) {
+      name = existing[0].name;
+      existing.push({ name, value });
+    } else {
+      this.headers.set(name.toLowerCase(), [{ name, value }]);
+    }
+  }
+
+  contains(name) {
+    return this.headers.has(name.toLowerCase());
+  }
+
+  get(name) {
+    name = name.toLowerCase();
+    const values = this.headers.get(name);
+    if (!values) {
+      return null;
+    }
+    return values.map(h => h.value).join(", ");
+  }
+
+  delete(name) {
+    this.headers.delete(name.toLowerCase());
+  }
+
+  set(name, value) {
+    const lowerName = name.toLowerCase();
+    this.headers.delete(lowerName);
+    this.headers.set(lowerName, [{ name, value }]);
+  }
+
+  sortAndCombine() {
+    const names = [...this.headers.keys()].sort();
+    return names.map(n => [n, this.get(n)]);
+  }
+}
+
+module.exports = HeaderList;
Index: frontend/node_modules/jsdom/lib/jsdom/living/fetch/header-types.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/fetch/header-types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/fetch/header-types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,103 @@
+"use strict";
+
+const MIMEType = require("whatwg-mimetype");
+
+const PRIVILEGED_NO_CORS_REQUEST = new Set(["range"]);
+function isPrivilegedNoCORSRequest(name) {
+  return PRIVILEGED_NO_CORS_REQUEST.has(name.toLowerCase());
+}
+
+const NO_CORS_SAFELISTED_REQUEST = new Set([
+  `accept`,
+  `accept-language`,
+  `content-language`,
+  `content-type`
+]);
+function isNoCORSSafelistedRequest(name) {
+  return NO_CORS_SAFELISTED_REQUEST.has(name.toLowerCase());
+}
+
+const FORBIDDEN = new Set([
+  `accept-charset`,
+  `accept-encoding`,
+  `access-control-request-headers`,
+  `access-control-request-method`,
+  `connection`,
+  `content-length`,
+  `cookie`,
+  `cookie2`,
+  `date`,
+  `dnt`,
+  `expect`,
+  `host`,
+  `keep-alive`,
+  `origin`,
+  `referer`,
+  `te`,
+  `trailer`,
+  `transfer-encoding`,
+  `upgrade`,
+  `via`
+]);
+function isForbidden(name) {
+  name = name.toLowerCase();
+  return (
+    FORBIDDEN.has(name) || name.startsWith("proxy-") || name.startsWith("sec-")
+  );
+}
+
+const FORBIDDEN_RESPONSE = new Set(["set-cookie", "set-cookie2"]);
+function isForbiddenResponse(name) {
+  return FORBIDDEN_RESPONSE.has(name.toLowerCase());
+}
+
+const CORS_UNSAFE_BYTE = /[\x00-\x08\x0A-\x1F"():<>?@[\\\]{}\x7F]/;
+function isCORSWhitelisted(name, value) {
+  name = name.toLowerCase();
+  switch (name) {
+    case "accept":
+      if (value.match(CORS_UNSAFE_BYTE)) {
+        return false;
+      }
+      break;
+    case "accept-language":
+    case "content-language":
+      if (value.match(/[^\x30-\x39\x41-\x5A\x61-\x7A *,\-.;=]/)) {
+        return false;
+      }
+      break;
+    case "content-type": {
+      if (value.match(CORS_UNSAFE_BYTE)) {
+        return false;
+      }
+      const mimeType = MIMEType.parse(value);
+      if (mimeType === null) {
+        return false;
+      }
+      if (
+        ![
+          "application/x-www-form-urlencoded",
+          "multipart/form-data",
+          "text/plain"
+        ].includes(mimeType.essence)
+      ) {
+        return false;
+      }
+      break;
+    }
+    default:
+      return false;
+  }
+  if (Buffer.from(value).length > 128) {
+    return false;
+  }
+  return true;
+}
+
+module.exports = {
+  isPrivilegedNoCORSRequest,
+  isNoCORSSafelistedRequest,
+  isForbidden,
+  isForbiddenResponse,
+  isCORSWhitelisted
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/file-api/Blob-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/file-api/Blob-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/file-api/Blob-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,93 @@
+"use strict";
+const Blob = require("../generated/Blob");
+const { isArrayBuffer } = require("../generated/utils");
+
+function convertLineEndingsToNative(s) {
+  // jsdom always pretends to be *nix, for consistency.
+  // See also https://github.com/jsdom/jsdom/issues/2396.
+  return s.replace(/\r\n|\r|\n/g, "\n");
+}
+
+exports.implementation = class BlobImpl {
+  constructor(globalObject, args) {
+    const parts = args[0];
+    const properties = args[1];
+
+    const buffers = [];
+
+    if (parts !== undefined) {
+      for (const part of parts) {
+        let buffer;
+        if (isArrayBuffer(part)) {
+          buffer = Buffer.from(part);
+        } else if (ArrayBuffer.isView(part)) {
+          buffer = Buffer.from(part.buffer, part.byteOffset, part.byteLength);
+        } else if (Blob.isImpl(part)) {
+          buffer = part._buffer;
+        } else {
+          let s = part;
+          if (properties.endings === "native") {
+            s = convertLineEndingsToNative(part);
+          }
+          buffer = Buffer.from(s);
+        }
+        buffers.push(buffer);
+      }
+    }
+
+    this._buffer = Buffer.concat(buffers);
+    this._globalObject = globalObject;
+
+    this.type = properties.type;
+    if (/[^\u0020-\u007E]/.test(this.type)) {
+      this.type = "";
+    } else {
+      this.type = this.type.toLowerCase();
+    }
+  }
+
+  get size() {
+    return this._buffer.length;
+  }
+
+  slice(start, end, contentType) {
+    const { size } = this;
+
+    let relativeStart, relativeEnd, relativeContentType;
+
+    if (start === undefined) {
+      relativeStart = 0;
+    } else if (start < 0) {
+      relativeStart = Math.max(size + start, 0);
+    } else {
+      relativeStart = Math.min(start, size);
+    }
+    if (end === undefined) {
+      relativeEnd = size;
+    } else if (end < 0) {
+      relativeEnd = Math.max(size + end, 0);
+    } else {
+      relativeEnd = Math.min(end, size);
+    }
+
+    if (contentType === undefined) {
+      relativeContentType = "";
+    } else {
+      // sanitization (lower case and invalid char check) is done in the
+      // constructor
+      relativeContentType = contentType;
+    }
+
+    const span = Math.max(relativeEnd - relativeStart, 0);
+
+    const buffer = this._buffer;
+    const slicedBuffer = buffer.slice(
+      relativeStart,
+      relativeStart + span
+    );
+
+    const blob = Blob.createImpl(this._globalObject, [[], { type: relativeContentType }], {});
+    blob._buffer = slicedBuffer;
+    return blob;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/file-api/File-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/file-api/File-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/file-api/File-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const BlobImpl = require("./Blob-impl").implementation;
+
+exports.implementation = class FileImpl extends BlobImpl {
+  constructor(globalObject, [fileBits, fileName, options], privateData) {
+    super(globalObject, [fileBits, options], privateData);
+
+    this.name = fileName;
+    this.lastModified = "lastModified" in options ? options.lastModified : Date.now();
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/file-api/FileList-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/file-api/FileList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/file-api/FileList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+
+exports.implementation = class FileListImpl extends Array {
+  constructor() {
+    super(0);
+  }
+  item(index) {
+    return this[index] || null;
+  }
+  get [idlUtils.supportedPropertyIndices]() {
+    return this.keys();
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/file-api/FileReader-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/file-api/FileReader-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/file-api/FileReader-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,130 @@
+"use strict";
+
+const whatwgEncoding = require("whatwg-encoding");
+const MIMEType = require("whatwg-mimetype");
+const DOMException = require("domexception/webidl2js-wrapper");
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+const ProgressEvent = require("../generated/ProgressEvent");
+const { setupForSimpleEventAccessors } = require("../helpers/create-event-accessor");
+const { fireAnEvent } = require("../helpers/events");
+const { copyToArrayBufferInNewRealm } = require("../helpers/binary-data");
+
+const READY_STATES = Object.freeze({
+  EMPTY: 0,
+  LOADING: 1,
+  DONE: 2
+});
+
+const events = ["loadstart", "progress", "load", "abort", "error", "loadend"];
+
+class FileReaderImpl extends EventTargetImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this.error = null;
+    this.readyState = READY_STATES.EMPTY;
+    this.result = null;
+
+    this._globalObject = globalObject;
+    this._ownerDocument = globalObject.document;
+    this._terminated = false;
+  }
+
+  readAsArrayBuffer(file) {
+    this._readFile(file, "buffer");
+  }
+  readAsBinaryString(file) {
+    this._readFile(file, "binaryString");
+  }
+  readAsDataURL(file) {
+    this._readFile(file, "dataURL");
+  }
+  readAsText(file, encoding) {
+    this._readFile(file, "text", whatwgEncoding.labelToName(encoding) || "UTF-8");
+  }
+
+  abort() {
+    if (this.readyState === READY_STATES.EMPTY || this.readyState === READY_STATES.DONE) {
+      this.result = null;
+      return;
+    }
+
+    if (this.readyState === READY_STATES.LOADING) {
+      this.readyState = READY_STATES.DONE;
+      this.result = null;
+    }
+
+    this._terminated = true;
+    this._fireProgressEvent("abort");
+    this._fireProgressEvent("loadend");
+  }
+
+  _fireProgressEvent(name, props) {
+    fireAnEvent(name, this, ProgressEvent, props);
+  }
+
+  _readFile(file, format, encoding) {
+    if (this.readyState === READY_STATES.LOADING) {
+      throw DOMException.create(this._globalObject, [
+        "The object is in an invalid state.",
+        "InvalidStateError"
+      ]);
+    }
+
+    this.readyState = READY_STATES.LOADING;
+
+    setImmediate(() => {
+      if (this._terminated) {
+        this._terminated = false;
+        return;
+      }
+
+      this._fireProgressEvent("loadstart");
+
+      let data = file._buffer;
+      if (!data) {
+        data = Buffer.alloc(0);
+      }
+      this._fireProgressEvent("progress", {
+        lengthComputable: !isNaN(file.size),
+        total: file.size,
+        loaded: data.length
+      });
+
+      setImmediate(() => {
+        if (this._terminated) {
+          this._terminated = false;
+          return;
+        }
+
+        switch (format) {
+          case "binaryString": {
+            this.result = data.toString("binary");
+            break;
+          }
+          case "dataURL": {
+            // Spec seems very unclear here; see https://github.com/w3c/FileAPI/issues/104.
+            const contentType = MIMEType.parse(file.type) || "application/octet-stream";
+            this.result = `data:${contentType};base64,${data.toString("base64")}`;
+            break;
+          }
+          case "text": {
+            this.result = whatwgEncoding.decode(data, encoding);
+            break;
+          }
+          case "buffer":
+          default: {
+            this.result = copyToArrayBufferInNewRealm(data, this._globalObject);
+            break;
+          }
+        }
+        this.readyState = READY_STATES.DONE;
+        this._fireProgressEvent("load");
+        this._fireProgressEvent("loadend");
+      });
+    });
+  }
+}
+setupForSimpleEventAccessors(FileReaderImpl.prototype, events);
+
+exports.implementation = FileReaderImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/AbortController.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/AbortController.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/AbortController.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,130 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "AbortController";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'AbortController'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["AbortController"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor AbortController is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class AbortController {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    abort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'abort' called on an object that is not a valid instance of AbortController.");
+      }
+
+      return esValue[implSymbol].abort();
+    }
+
+    get signal() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get signal' called on an object that is not a valid instance of AbortController.");
+      }
+
+      return utils.getSameObject(this, "signal", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["signal"]);
+      });
+    }
+  }
+  Object.defineProperties(AbortController.prototype, {
+    abort: { enumerable: true },
+    signal: { enumerable: true },
+    [Symbol.toStringTag]: { value: "AbortController", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = AbortController;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: AbortController
+  });
+};
+
+const Impl = require("../aborting/AbortController-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/AbortSignal.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/AbortSignal.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/AbortSignal.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,159 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const EventTarget = require("./EventTarget.js");
+
+const interfaceName = "AbortSignal";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'AbortSignal'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["AbortSignal"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor AbortSignal is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  EventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.EventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate AbortSignal before EventTarget");
+  }
+  class AbortSignal extends globalObject.EventTarget {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get aborted() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get aborted' called on an object that is not a valid instance of AbortSignal.");
+      }
+
+      return esValue[implSymbol]["aborted"];
+    }
+
+    get onabort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onabort' called on an object that is not a valid instance of AbortSignal.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onabort"]);
+    }
+
+    set onabort(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onabort' called on an object that is not a valid instance of AbortSignal.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onabort' property on 'AbortSignal': The provided value"
+        });
+      }
+      esValue[implSymbol]["onabort"] = V;
+    }
+
+    static abort() {
+      return utils.tryWrapperForImpl(Impl.implementation.abort(globalObject));
+    }
+  }
+  Object.defineProperties(AbortSignal.prototype, {
+    aborted: { enumerable: true },
+    onabort: { enumerable: true },
+    [Symbol.toStringTag]: { value: "AbortSignal", configurable: true }
+  });
+  Object.defineProperties(AbortSignal, { abort: { enumerable: true } });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = AbortSignal;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: AbortSignal
+  });
+};
+
+const Impl = require("../aborting/AbortSignal-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/AbstractRange.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/AbstractRange.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/AbstractRange.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,162 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "AbstractRange";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'AbstractRange'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["AbstractRange"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor AbstractRange is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class AbstractRange {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get startContainer() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get startContainer' called on an object that is not a valid instance of AbstractRange.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["startContainer"]);
+    }
+
+    get startOffset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get startOffset' called on an object that is not a valid instance of AbstractRange.");
+      }
+
+      return esValue[implSymbol]["startOffset"];
+    }
+
+    get endContainer() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get endContainer' called on an object that is not a valid instance of AbstractRange.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["endContainer"]);
+    }
+
+    get endOffset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get endOffset' called on an object that is not a valid instance of AbstractRange.");
+      }
+
+      return esValue[implSymbol]["endOffset"];
+    }
+
+    get collapsed() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get collapsed' called on an object that is not a valid instance of AbstractRange.");
+      }
+
+      return esValue[implSymbol]["collapsed"];
+    }
+  }
+  Object.defineProperties(AbstractRange.prototype, {
+    startContainer: { enumerable: true },
+    startOffset: { enumerable: true },
+    endContainer: { enumerable: true },
+    endOffset: { enumerable: true },
+    collapsed: { enumerable: true },
+    [Symbol.toStringTag]: { value: "AbstractRange", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = AbstractRange;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: AbstractRange
+  });
+};
+
+const Impl = require("../range/AbstractRange-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/AddEventListenerOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/AddEventListenerOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/AddEventListenerOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventListenerOptions = require("./EventListenerOptions.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventListenerOptions._convertInherit(obj, ret, { context });
+
+  {
+    const key = "once";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'once' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "passive";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'passive' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/AssignedNodesOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/AssignedNodesOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/AssignedNodesOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "flatten";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'flatten' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Attr.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Attr.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Attr.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,215 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Node = require("./Node.js");
+
+const interfaceName = "Attr";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Attr'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Attr"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Attr is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Node._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Node === undefined) {
+    throw new Error("Internal error: attempting to evaluate Attr before Node");
+  }
+  class Attr extends globalObject.Node {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get namespaceURI() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get namespaceURI' called on an object that is not a valid instance of Attr.");
+      }
+
+      return esValue[implSymbol]["namespaceURI"];
+    }
+
+    get prefix() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get prefix' called on an object that is not a valid instance of Attr.");
+      }
+
+      return esValue[implSymbol]["prefix"];
+    }
+
+    get localName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get localName' called on an object that is not a valid instance of Attr.");
+      }
+
+      return esValue[implSymbol]["localName"];
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of Attr.");
+      }
+
+      return esValue[implSymbol]["name"];
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of Attr.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of Attr.");
+      }
+
+      V = conversions["DOMString"](V, { context: "Failed to set the 'value' property on 'Attr': The provided value" });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get ownerElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ownerElement' called on an object that is not a valid instance of Attr.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ownerElement"]);
+    }
+
+    get specified() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get specified' called on an object that is not a valid instance of Attr.");
+      }
+
+      return esValue[implSymbol]["specified"];
+    }
+  }
+  Object.defineProperties(Attr.prototype, {
+    namespaceURI: { enumerable: true },
+    prefix: { enumerable: true },
+    localName: { enumerable: true },
+    name: { enumerable: true },
+    value: { enumerable: true },
+    ownerElement: { enumerable: true },
+    specified: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Attr", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Attr;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Attr
+  });
+};
+
+const Impl = require("../attributes/Attr-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/BarProp.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/BarProp.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/BarProp.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,118 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "BarProp";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'BarProp'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["BarProp"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor BarProp is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class BarProp {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get visible() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get visible' called on an object that is not a valid instance of BarProp.");
+      }
+
+      return esValue[implSymbol]["visible"];
+    }
+  }
+  Object.defineProperties(BarProp.prototype, {
+    visible: { enumerable: true },
+    [Symbol.toStringTag]: { value: "BarProp", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = BarProp;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: BarProp
+  });
+};
+
+const Impl = require("../window/BarProp-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/BinaryType.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/BinaryType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/BinaryType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["blob", "arraybuffer"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for BinaryType`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Blob.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Blob.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Blob.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,198 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const BlobPropertyBag = require("./BlobPropertyBag.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Blob";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Blob'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Blob"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Blob is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Blob {
+    constructor() {
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          if (!utils.isObject(curArg)) {
+            throw new TypeError("Failed to construct 'Blob': parameter 1" + " is not an iterable object.");
+          } else {
+            const V = [];
+            const tmp = curArg;
+            for (let nextItem of tmp) {
+              if (exports.is(nextItem)) {
+                nextItem = utils.implForWrapper(nextItem);
+              } else if (utils.isArrayBuffer(nextItem)) {
+              } else if (ArrayBuffer.isView(nextItem)) {
+              } else {
+                nextItem = conversions["USVString"](nextItem, {
+                  context: "Failed to construct 'Blob': parameter 1" + "'s element"
+                });
+              }
+              V.push(nextItem);
+            }
+            curArg = V;
+          }
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = BlobPropertyBag.convert(curArg, { context: "Failed to construct 'Blob': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    slice() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'slice' called on an object that is not a valid instance of Blob.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long long"](curArg, {
+            context: "Failed to execute 'slice' on 'Blob': parameter 1",
+            clamp: true
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["long long"](curArg, {
+            context: "Failed to execute 'slice' on 'Blob': parameter 2",
+            clamp: true
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'slice' on 'Blob': parameter 3" });
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].slice(...args));
+    }
+
+    get size() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get size' called on an object that is not a valid instance of Blob.");
+      }
+
+      return esValue[implSymbol]["size"];
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of Blob.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+  }
+  Object.defineProperties(Blob.prototype, {
+    slice: { enumerable: true },
+    size: { enumerable: true },
+    type: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Blob", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Blob;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Blob
+  });
+};
+
+const Impl = require("../file-api/Blob-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/BlobCallback.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/BlobCallback.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/BlobCallback.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,34 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (typeof value !== "function") {
+    throw new TypeError(context + " is not a function");
+  }
+
+  function invokeTheCallbackFunction(blob) {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    blob = utils.tryWrapperForImpl(blob);
+
+    callResult = Reflect.apply(value, thisArg, [blob]);
+  }
+
+  invokeTheCallbackFunction.construct = blob => {
+    blob = utils.tryWrapperForImpl(blob);
+
+    let callResult = Reflect.construct(value, [blob]);
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/BlobPropertyBag.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/BlobPropertyBag.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/BlobPropertyBag.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,42 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EndingType = require("./EndingType.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "endings";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = EndingType.convert(value, { context: context + " has member 'endings' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "transparent";
+    }
+  }
+
+  {
+    const key = "type";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'type' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CDATASection.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CDATASection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CDATASection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Text = require("./Text.js");
+
+const interfaceName = "CDATASection";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'CDATASection'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["CDATASection"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor CDATASection is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Text._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Text === undefined) {
+    throw new Error("Internal error: attempting to evaluate CDATASection before Text");
+  }
+  class CDATASection extends globalObject.Text {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(CDATASection.prototype, {
+    [Symbol.toStringTag]: { value: "CDATASection", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = CDATASection;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: CDATASection
+  });
+};
+
+const Impl = require("../nodes/CDATASection-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CanPlayTypeResult.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CanPlayTypeResult.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CanPlayTypeResult.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["", "maybe", "probably"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for CanPlayTypeResult`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CharacterData.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CharacterData.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CharacterData.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,436 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "CharacterData";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'CharacterData'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["CharacterData"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor CharacterData is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Node._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Node === undefined) {
+    throw new Error("Internal error: attempting to evaluate CharacterData before Node");
+  }
+  class CharacterData extends globalObject.Node {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    substringData(offset, count) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'substringData' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'substringData' on 'CharacterData': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'substringData' on 'CharacterData': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'substringData' on 'CharacterData': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].substringData(...args);
+    }
+
+    appendData(data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'appendData' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'appendData' on 'CharacterData': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'appendData' on 'CharacterData': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].appendData(...args);
+    }
+
+    insertData(offset, data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertData' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'insertData' on 'CharacterData': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'insertData' on 'CharacterData': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertData' on 'CharacterData': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].insertData(...args);
+    }
+
+    deleteData(offset, count) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteData' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'deleteData' on 'CharacterData': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'deleteData' on 'CharacterData': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'deleteData' on 'CharacterData': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].deleteData(...args);
+    }
+
+    replaceData(offset, count, data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceData' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      if (arguments.length < 3) {
+        throw new TypeError(
+          "Failed to execute 'replaceData' on 'CharacterData': 3 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'replaceData' on 'CharacterData': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'replaceData' on 'CharacterData': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'replaceData' on 'CharacterData': parameter 3"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].replaceData(...args);
+    }
+
+    before() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'before' called on an object that is not a valid instance of CharacterData.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'before' on 'CharacterData': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].before(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    after() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'after' called on an object that is not a valid instance of CharacterData.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'after' on 'CharacterData': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].after(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceWith() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceWith' called on an object that is not a valid instance of CharacterData.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'replaceWith' on 'CharacterData': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].replaceWith(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    remove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'remove' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].remove();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get data() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get data' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      return esValue[implSymbol]["data"];
+    }
+
+    set data(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set data' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'data' property on 'CharacterData': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      esValue[implSymbol]["data"] = V;
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of CharacterData.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+
+    get previousElementSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get previousElementSibling' called on an object that is not a valid instance of CharacterData."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["previousElementSibling"]);
+    }
+
+    get nextElementSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get nextElementSibling' called on an object that is not a valid instance of CharacterData."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["nextElementSibling"]);
+    }
+  }
+  Object.defineProperties(CharacterData.prototype, {
+    substringData: { enumerable: true },
+    appendData: { enumerable: true },
+    insertData: { enumerable: true },
+    deleteData: { enumerable: true },
+    replaceData: { enumerable: true },
+    before: { enumerable: true },
+    after: { enumerable: true },
+    replaceWith: { enumerable: true },
+    remove: { enumerable: true },
+    data: { enumerable: true },
+    length: { enumerable: true },
+    previousElementSibling: { enumerable: true },
+    nextElementSibling: { enumerable: true },
+    [Symbol.toStringTag]: { value: "CharacterData", configurable: true },
+    [Symbol.unscopables]: {
+      value: { before: true, after: true, replaceWith: true, remove: true, __proto__: null },
+      configurable: true
+    }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = CharacterData;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: CharacterData
+  });
+};
+
+const Impl = require("../nodes/CharacterData-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CloseEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CloseEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CloseEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,164 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const CloseEventInit = require("./CloseEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "CloseEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'CloseEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["CloseEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor CloseEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate CloseEvent before Event");
+  }
+  class CloseEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'CloseEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'CloseEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = CloseEventInit.convert(curArg, { context: "Failed to construct 'CloseEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get wasClean() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get wasClean' called on an object that is not a valid instance of CloseEvent.");
+      }
+
+      return esValue[implSymbol]["wasClean"];
+    }
+
+    get code() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get code' called on an object that is not a valid instance of CloseEvent.");
+      }
+
+      return esValue[implSymbol]["code"];
+    }
+
+    get reason() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get reason' called on an object that is not a valid instance of CloseEvent.");
+      }
+
+      return esValue[implSymbol]["reason"];
+    }
+  }
+  Object.defineProperties(CloseEvent.prototype, {
+    wasClean: { enumerable: true },
+    code: { enumerable: true },
+    reason: { enumerable: true },
+    [Symbol.toStringTag]: { value: "CloseEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = CloseEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: CloseEvent
+  });
+};
+
+const Impl = require("../events/CloseEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CloseEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CloseEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CloseEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,56 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "code";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned short"](value, { context: context + " has member 'code' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "reason";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["USVString"](value, { context: context + " has member 'reason' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "wasClean";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'wasClean' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Comment.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Comment.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Comment.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,122 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const CharacterData = require("./CharacterData.js");
+
+const interfaceName = "Comment";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Comment'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Comment"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Comment is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  CharacterData._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.CharacterData === undefined) {
+    throw new Error("Internal error: attempting to evaluate Comment before CharacterData");
+  }
+  class Comment extends globalObject.CharacterData {
+    constructor() {
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'Comment': parameter 1" });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+  }
+  Object.defineProperties(Comment.prototype, { [Symbol.toStringTag]: { value: "Comment", configurable: true } });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Comment;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Comment
+  });
+};
+
+const Impl = require("../nodes/Comment-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CompositionEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CompositionEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CompositionEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,217 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const CompositionEventInit = require("./CompositionEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const UIEvent = require("./UIEvent.js");
+
+const interfaceName = "CompositionEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'CompositionEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["CompositionEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor CompositionEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  UIEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.UIEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate CompositionEvent before UIEvent");
+  }
+  class CompositionEvent extends globalObject.UIEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'CompositionEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'CompositionEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = CompositionEventInit.convert(curArg, {
+          context: "Failed to construct 'CompositionEvent': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    initCompositionEvent(typeArg) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'initCompositionEvent' called on an object that is not a valid instance of CompositionEvent."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initCompositionEvent' on 'CompositionEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initCompositionEvent' on 'CompositionEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initCompositionEvent' on 'CompositionEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initCompositionEvent' on 'CompositionEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = utils.tryImplForWrapper(curArg);
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[4];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'initCompositionEvent' on 'CompositionEvent': parameter 5"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initCompositionEvent(...args);
+    }
+
+    get data() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get data' called on an object that is not a valid instance of CompositionEvent.");
+      }
+
+      return esValue[implSymbol]["data"];
+    }
+  }
+  Object.defineProperties(CompositionEvent.prototype, {
+    initCompositionEvent: { enumerable: true },
+    data: { enumerable: true },
+    [Symbol.toStringTag]: { value: "CompositionEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = CompositionEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: CompositionEvent
+  });
+};
+
+const Impl = require("../events/CompositionEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CompositionEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CompositionEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CompositionEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const UIEventInit = require("./UIEventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  UIEventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "data";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'data' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomElementConstructor.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomElementConstructor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomElementConstructor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (typeof value !== "function") {
+    throw new TypeError(context + " is not a function");
+  }
+
+  function invokeTheCallbackFunction() {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    callResult = Reflect.apply(value, thisArg, []);
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  }
+
+  invokeTheCallbackFunction.construct = () => {
+    let callResult = Reflect.construct(value, []);
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomElementRegistry.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomElementRegistry.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomElementRegistry.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,242 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const CustomElementConstructor = require("./CustomElementConstructor.js");
+const ElementDefinitionOptions = require("./ElementDefinitionOptions.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const Node = require("./Node.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "CustomElementRegistry";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'CustomElementRegistry'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["CustomElementRegistry"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor CustomElementRegistry is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class CustomElementRegistry {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    define(name, constructor) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'define' called on an object that is not a valid instance of CustomElementRegistry.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'define' on 'CustomElementRegistry': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'define' on 'CustomElementRegistry': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = CustomElementConstructor.convert(curArg, {
+          context: "Failed to execute 'define' on 'CustomElementRegistry': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        curArg = ElementDefinitionOptions.convert(curArg, {
+          context: "Failed to execute 'define' on 'CustomElementRegistry': parameter 3"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].define(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get' called on an object that is not a valid instance of CustomElementRegistry.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'get' on 'CustomElementRegistry': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'get' on 'CustomElementRegistry': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].get(...args);
+    }
+
+    whenDefined(name) {
+      try {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+        if (!exports.is(esValue)) {
+          throw new TypeError(
+            "'whenDefined' called on an object that is not a valid instance of CustomElementRegistry."
+          );
+        }
+
+        if (arguments.length < 1) {
+          throw new TypeError(
+            "Failed to execute 'whenDefined' on 'CustomElementRegistry': 1 argument required, but only " +
+              arguments.length +
+              " present."
+          );
+        }
+        const args = [];
+        {
+          let curArg = arguments[0];
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'whenDefined' on 'CustomElementRegistry': parameter 1"
+          });
+          args.push(curArg);
+        }
+        return utils.tryWrapperForImpl(esValue[implSymbol].whenDefined(...args));
+      } catch (e) {
+        return Promise.reject(e);
+      }
+    }
+
+    upgrade(root) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'upgrade' called on an object that is not a valid instance of CustomElementRegistry.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'upgrade' on 'CustomElementRegistry': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, {
+          context: "Failed to execute 'upgrade' on 'CustomElementRegistry': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].upgrade(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(CustomElementRegistry.prototype, {
+    define: { enumerable: true },
+    get: { enumerable: true },
+    whenDefined: { enumerable: true },
+    upgrade: { enumerable: true },
+    [Symbol.toStringTag]: { value: "CustomElementRegistry", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = CustomElementRegistry;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: CustomElementRegistry
+  });
+};
+
+const Impl = require("../custom-elements/CustomElementRegistry-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,200 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const CustomEventInit = require("./CustomEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "CustomEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'CustomEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["CustomEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor CustomEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate CustomEvent before Event");
+  }
+  class CustomEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'CustomEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'CustomEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = CustomEventInit.convert(curArg, { context: "Failed to construct 'CustomEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    initCustomEvent(type) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initCustomEvent' called on an object that is not a valid instance of CustomEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initCustomEvent' on 'CustomEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initCustomEvent' on 'CustomEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initCustomEvent' on 'CustomEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initCustomEvent' on 'CustomEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          curArg = conversions["any"](curArg, {
+            context: "Failed to execute 'initCustomEvent' on 'CustomEvent': parameter 4"
+          });
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initCustomEvent(...args);
+    }
+
+    get detail() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get detail' called on an object that is not a valid instance of CustomEvent.");
+      }
+
+      return esValue[implSymbol]["detail"];
+    }
+  }
+  Object.defineProperties(CustomEvent.prototype, {
+    initCustomEvent: { enumerable: true },
+    detail: { enumerable: true },
+    [Symbol.toStringTag]: { value: "CustomEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = CustomEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: CustomEvent
+  });
+};
+
+const Impl = require("../events/CustomEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/CustomEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "detail";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["any"](value, { context: context + " has member 'detail' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMImplementation.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMImplementation.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMImplementation.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,232 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const DocumentType = require("./DocumentType.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "DOMImplementation";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'DOMImplementation'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["DOMImplementation"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor DOMImplementation is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class DOMImplementation {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    createDocumentType(qualifiedName, publicId, systemId) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'createDocumentType' called on an object that is not a valid instance of DOMImplementation."
+        );
+      }
+
+      if (arguments.length < 3) {
+        throw new TypeError(
+          "Failed to execute 'createDocumentType' on 'DOMImplementation': 3 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createDocumentType' on 'DOMImplementation': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createDocumentType' on 'DOMImplementation': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createDocumentType' on 'DOMImplementation': parameter 3"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createDocumentType(...args));
+    }
+
+    createDocument(namespace, qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createDocument' called on an object that is not a valid instance of DOMImplementation.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'createDocument' on 'DOMImplementation': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'createDocument' on 'DOMImplementation': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createDocument' on 'DOMImplementation': parameter 2",
+          treatNullAsEmptyString: true
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = DocumentType.convert(curArg, {
+              context: "Failed to execute 'createDocument' on 'DOMImplementation': parameter 3"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createDocument(...args));
+    }
+
+    createHTMLDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'createHTMLDocument' called on an object that is not a valid instance of DOMImplementation."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'createHTMLDocument' on 'DOMImplementation': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createHTMLDocument(...args));
+    }
+
+    hasFeature() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'hasFeature' called on an object that is not a valid instance of DOMImplementation.");
+      }
+
+      return esValue[implSymbol].hasFeature();
+    }
+  }
+  Object.defineProperties(DOMImplementation.prototype, {
+    createDocumentType: { enumerable: true },
+    createDocument: { enumerable: true },
+    createHTMLDocument: { enumerable: true },
+    hasFeature: { enumerable: true },
+    [Symbol.toStringTag]: { value: "DOMImplementation", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = DOMImplementation;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: DOMImplementation
+  });
+};
+
+const Impl = require("../nodes/DOMImplementation-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMParser.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMParser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMParser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,140 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const SupportedType = require("./SupportedType.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "DOMParser";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'DOMParser'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["DOMParser"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor DOMParser is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class DOMParser {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    parseFromString(str, type) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'parseFromString' called on an object that is not a valid instance of DOMParser.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'parseFromString' on 'DOMParser': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'parseFromString' on 'DOMParser': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = SupportedType.convert(curArg, {
+          context: "Failed to execute 'parseFromString' on 'DOMParser': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].parseFromString(...args));
+    }
+  }
+  Object.defineProperties(DOMParser.prototype, {
+    parseFromString: { enumerable: true },
+    [Symbol.toStringTag]: { value: "DOMParser", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = DOMParser;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: DOMParser
+  });
+};
+
+const Impl = require("../domparsing/DOMParser-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMStringMap.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMStringMap.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMStringMap.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,322 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "DOMStringMap";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'DOMStringMap'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["DOMStringMap"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor DOMStringMap is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+function makeProxy(wrapper, globalObject) {
+  let proxyHandler = proxyHandlerCache.get(globalObject);
+  if (proxyHandler === undefined) {
+    proxyHandler = new ProxyHandler(globalObject);
+    proxyHandlerCache.set(globalObject, proxyHandler);
+  }
+  return new Proxy(wrapper, proxyHandler);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = makeProxy(wrapper, globalObject);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = makeProxy(wrapper, globalObject);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class DOMStringMap {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(DOMStringMap.prototype, {
+    [Symbol.toStringTag]: { value: "DOMStringMap", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = DOMStringMap;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: DOMStringMap
+  });
+};
+
+const proxyHandlerCache = new WeakMap();
+class ProxyHandler {
+  constructor(globalObject) {
+    this._globalObject = globalObject;
+  }
+
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  }
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  }
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyNames]) {
+      if (!utils.hasOwn(target, key)) {
+        keys.add(`${key}`);
+      }
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  }
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    const namedValue = target[implSymbol][utils.namedGet](P);
+
+    if (namedValue !== undefined && !utils.hasOwn(target, P) && !ignoreNamedProps) {
+      return {
+        writable: true,
+        enumerable: true,
+        configurable: true,
+        value: utils.tryWrapperForImpl(namedValue)
+      };
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  }
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+      const globalObject = this._globalObject;
+
+      if (typeof P === "string") {
+        let namedValue = V;
+
+        namedValue = conversions["DOMString"](namedValue, {
+          context: "Failed to set the '" + P + "' property on 'DOMStringMap': The provided value"
+        });
+
+        ceReactionsPreSteps_helpers_custom_elements(globalObject);
+        try {
+          const creating = !(target[implSymbol][utils.namedGet](P) !== undefined);
+          if (creating) {
+            target[implSymbol][utils.namedSetNew](P, namedValue);
+          } else {
+            target[implSymbol][utils.namedSetExisting](P, namedValue);
+          }
+        } finally {
+          ceReactionsPostSteps_helpers_custom_elements(globalObject);
+        }
+
+        return true;
+      }
+    }
+    let ownDesc;
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  }
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    const globalObject = this._globalObject;
+
+    if (desc.get || desc.set) {
+      return false;
+    }
+
+    let namedValue = desc.value;
+
+    namedValue = conversions["DOMString"](namedValue, {
+      context: "Failed to set the '" + P + "' property on 'DOMStringMap': The provided value"
+    });
+
+    ceReactionsPreSteps_helpers_custom_elements(globalObject);
+    try {
+      const creating = !(target[implSymbol][utils.namedGet](P) !== undefined);
+      if (creating) {
+        target[implSymbol][utils.namedSetNew](P, namedValue);
+      } else {
+        target[implSymbol][utils.namedSetExisting](P, namedValue);
+      }
+    } finally {
+      ceReactionsPostSteps_helpers_custom_elements(globalObject);
+    }
+
+    return true;
+  }
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    const globalObject = this._globalObject;
+
+    if (target[implSymbol][utils.namedGet](P) !== undefined && !utils.hasOwn(target, P)) {
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        target[implSymbol][utils.namedDelete](P);
+        return true;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    return Reflect.deleteProperty(target, P);
+  }
+
+  preventExtensions() {
+    return false;
+  }
+}
+
+const Impl = require("../nodes/DOMStringMap-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMTokenList.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMTokenList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DOMTokenList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,531 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "DOMTokenList";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'DOMTokenList'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["DOMTokenList"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor DOMTokenList is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class DOMTokenList {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'DOMTokenList': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'DOMTokenList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].item(...args);
+    }
+
+    contains(token) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'contains' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'contains' on 'DOMTokenList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'contains' on 'DOMTokenList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].contains(...args);
+    }
+
+    add() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'add' called on an object that is not a valid instance of DOMTokenList.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'add' on 'DOMTokenList': parameter " + (i + 1)
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].add(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    remove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'remove' called on an object that is not a valid instance of DOMTokenList.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'remove' on 'DOMTokenList': parameter " + (i + 1)
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].remove(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    toggle(token) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toggle' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'toggle' on 'DOMTokenList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'toggle' on 'DOMTokenList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'toggle' on 'DOMTokenList': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].toggle(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replace(token, newToken) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replace' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'replace' on 'DOMTokenList': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'replace' on 'DOMTokenList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'replace' on 'DOMTokenList': parameter 2"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].replace(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    supports(token) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'supports' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'supports' on 'DOMTokenList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'supports' on 'DOMTokenList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].supports(...args);
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'DOMTokenList': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    toString() {
+      const esValue = this;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toString' called on an object that is not a valid instance of DOMTokenList.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(DOMTokenList.prototype, {
+    item: { enumerable: true },
+    contains: { enumerable: true },
+    add: { enumerable: true },
+    remove: { enumerable: true },
+    toggle: { enumerable: true },
+    replace: { enumerable: true },
+    supports: { enumerable: true },
+    length: { enumerable: true },
+    value: { enumerable: true },
+    toString: { enumerable: true },
+    [Symbol.toStringTag]: { value: "DOMTokenList", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true },
+    keys: { value: Array.prototype.keys, configurable: true, enumerable: true, writable: true },
+    values: { value: Array.prototype[Symbol.iterator], configurable: true, enumerable: true, writable: true },
+    entries: { value: Array.prototype.entries, configurable: true, enumerable: true, writable: true },
+    forEach: { value: Array.prototype.forEach, configurable: true, enumerable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = DOMTokenList;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: DOMTokenList
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../nodes/DOMTokenList-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Document.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Document.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Document.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3322 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ElementCreationOptions = require("./ElementCreationOptions.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const Node = require("./Node.js");
+const NodeFilter = require("./NodeFilter.js");
+const HTMLElement = require("./HTMLElement.js");
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const OnErrorEventHandlerNonNull = require("./OnErrorEventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Document";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Document'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Document"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Document is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Node._internalSetup(wrapper, globalObject);
+
+  Object.defineProperties(
+    wrapper,
+    Object.getOwnPropertyDescriptors({
+      get location() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get location' called on an object that is not a valid instance of Document.");
+        }
+
+        return utils.tryWrapperForImpl(esValue[implSymbol]["location"]);
+      },
+      set location(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set location' called on an object that is not a valid instance of Document.");
+        }
+
+        const Q = esValue["location"];
+        if (!utils.isObject(Q)) {
+          throw new TypeError("Property 'location' is not an object");
+        }
+        Reflect.set(Q, "href", V);
+      }
+    })
+  );
+
+  Object.defineProperties(wrapper, { location: { configurable: false } });
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Node === undefined) {
+    throw new Error("Internal error: attempting to evaluate Document before Node");
+  }
+  class Document extends globalObject.Node {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    getElementsByTagName(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByTagName' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByTagName' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByTagName' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByTagName(...args));
+    }
+
+    getElementsByTagNameNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByTagNameNS' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByTagNameNS' on 'Document': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'getElementsByTagNameNS' on 'Document': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByTagNameNS' on 'Document': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByTagNameNS(...args));
+    }
+
+    getElementsByClassName(classNames) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByClassName' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByClassName' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByClassName' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByClassName(...args));
+    }
+
+    createElement(localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createElement' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createElement' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createElement' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = ElementCreationOptions.convert(curArg, {
+              context: "Failed to execute 'createElement' on 'Document': parameter 2"
+            });
+          } else if (utils.isObject(curArg)) {
+            curArg = ElementCreationOptions.convert(curArg, {
+              context: "Failed to execute 'createElement' on 'Document': parameter 2" + " dictionary"
+            });
+          } else {
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'createElement' on 'Document': parameter 2"
+            });
+          }
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].createElement(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    createElementNS(namespace, qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createElementNS' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'createElementNS' on 'Document': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'createElementNS' on 'Document': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createElementNS' on 'Document': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = ElementCreationOptions.convert(curArg, {
+              context: "Failed to execute 'createElementNS' on 'Document': parameter 3"
+            });
+          } else if (utils.isObject(curArg)) {
+            curArg = ElementCreationOptions.convert(curArg, {
+              context: "Failed to execute 'createElementNS' on 'Document': parameter 3" + " dictionary"
+            });
+          } else {
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'createElementNS' on 'Document': parameter 3"
+            });
+          }
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].createElementNS(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    createDocumentFragment() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createDocumentFragment' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createDocumentFragment());
+    }
+
+    createTextNode(data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createTextNode' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createTextNode' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createTextNode' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createTextNode(...args));
+    }
+
+    createCDATASection(data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createCDATASection' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createCDATASection' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createCDATASection' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createCDATASection(...args));
+    }
+
+    createComment(data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createComment' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createComment' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createComment' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createComment(...args));
+    }
+
+    createProcessingInstruction(target, data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'createProcessingInstruction' called on an object that is not a valid instance of Document."
+        );
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'createProcessingInstruction' on 'Document': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createProcessingInstruction' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createProcessingInstruction' on 'Document': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createProcessingInstruction(...args));
+    }
+
+    importNode(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'importNode' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'importNode' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'importNode' on 'Document': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'importNode' on 'Document': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].importNode(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    adoptNode(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'adoptNode' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'adoptNode' on 'Document': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'adoptNode' on 'Document': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].adoptNode(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    createAttribute(localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createAttribute' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createAttribute' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createAttribute' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createAttribute(...args));
+    }
+
+    createAttributeNS(namespace, qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createAttributeNS' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'createAttributeNS' on 'Document': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'createAttributeNS' on 'Document': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createAttributeNS' on 'Document': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createAttributeNS(...args));
+    }
+
+    createEvent(interface_) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createEvent' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createEvent' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createEvent' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createEvent(...args));
+    }
+
+    createRange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createRange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createRange());
+    }
+
+    createNodeIterator(root) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createNodeIterator' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createNodeIterator' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'createNodeIterator' on 'Document': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned long"](curArg, {
+            context: "Failed to execute 'createNodeIterator' on 'Document': parameter 2"
+          });
+        } else {
+          curArg = 0xffffffff;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = NodeFilter.convert(curArg, {
+              context: "Failed to execute 'createNodeIterator' on 'Document': parameter 3"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createNodeIterator(...args));
+    }
+
+    createTreeWalker(root) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createTreeWalker' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createTreeWalker' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'createTreeWalker' on 'Document': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned long"](curArg, {
+            context: "Failed to execute 'createTreeWalker' on 'Document': parameter 2"
+          });
+        } else {
+          curArg = 0xffffffff;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = NodeFilter.convert(curArg, {
+              context: "Failed to execute 'createTreeWalker' on 'Document': parameter 3"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].createTreeWalker(...args));
+    }
+
+    getElementsByName(elementName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByName' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByName' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByName' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByName(...args));
+    }
+
+    open() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'open' called on an object that is not a valid instance of Document.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'open' on 'Document': parameter 1" });
+        } else {
+          curArg = "text/html";
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'open' on 'Document': parameter 2" });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].open(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    close() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'close' called on an object that is not a valid instance of Document.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].close();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    write() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'write' called on an object that is not a valid instance of Document.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'write' on 'Document': parameter " + (i + 1)
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].write(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    writeln() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'writeln' called on an object that is not a valid instance of Document.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'writeln' on 'Document': parameter " + (i + 1)
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].writeln(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    hasFocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'hasFocus' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol].hasFocus();
+    }
+
+    clear() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'clear' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol].clear();
+    }
+
+    captureEvents() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'captureEvents' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol].captureEvents();
+    }
+
+    releaseEvents() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'releaseEvents' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol].releaseEvents();
+    }
+
+    getSelection() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getSelection' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].getSelection());
+    }
+
+    getElementById(elementId) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementById' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementById' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementById' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementById(...args));
+    }
+
+    prepend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'prepend' called on an object that is not a valid instance of Document.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'prepend' on 'Document': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].prepend(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    append() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'append' called on an object that is not a valid instance of Document.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'append' on 'Document': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].append(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceChildren() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceChildren' called on an object that is not a valid instance of Document.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'replaceChildren' on 'Document': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].replaceChildren(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    querySelector(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'querySelector' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'querySelector' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'querySelector' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].querySelector(...args));
+    }
+
+    querySelectorAll(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'querySelectorAll' called on an object that is not a valid instance of Document.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'querySelectorAll' on 'Document': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'querySelectorAll' on 'Document': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].querySelectorAll(...args));
+    }
+
+    get implementation() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get implementation' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "implementation", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["implementation"]);
+      });
+    }
+
+    get URL() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get URL' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["URL"];
+    }
+
+    get documentURI() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get documentURI' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["documentURI"];
+    }
+
+    get compatMode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get compatMode' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["compatMode"];
+    }
+
+    get characterSet() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get characterSet' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["characterSet"];
+    }
+
+    get charset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get charset' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["charset"];
+    }
+
+    get inputEncoding() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get inputEncoding' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["inputEncoding"];
+    }
+
+    get contentType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get contentType' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["contentType"];
+    }
+
+    get doctype() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get doctype' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["doctype"]);
+    }
+
+    get documentElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get documentElement' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["documentElement"]);
+    }
+
+    get referrer() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get referrer' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["referrer"];
+    }
+
+    get cookie() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cookie' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["cookie"];
+    }
+
+    set cookie(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cookie' called on an object that is not a valid instance of Document.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'cookie' property on 'Document': The provided value"
+      });
+
+      esValue[implSymbol]["cookie"] = V;
+    }
+
+    get lastModified() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lastModified' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["lastModified"];
+    }
+
+    get readyState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readyState' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["readyState"]);
+    }
+
+    get title() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get title' called on an object that is not a valid instance of Document.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["title"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set title(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set title' called on an object that is not a valid instance of Document.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'title' property on 'Document': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["title"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get dir() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dir' called on an object that is not a valid instance of Document.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["dir"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set dir(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set dir' called on an object that is not a valid instance of Document.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'dir' property on 'Document': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["dir"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get body() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get body' called on an object that is not a valid instance of Document.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["body"]);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set body(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set body' called on an object that is not a valid instance of Document.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = HTMLElement.convert(V, { context: "Failed to set the 'body' property on 'Document': The provided value" });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["body"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get head() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get head' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["head"]);
+    }
+
+    get images() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get images' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "images", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["images"]);
+      });
+    }
+
+    get embeds() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get embeds' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "embeds", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["embeds"]);
+      });
+    }
+
+    get plugins() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get plugins' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "plugins", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["plugins"]);
+      });
+    }
+
+    get links() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get links' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "links", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["links"]);
+      });
+    }
+
+    get forms() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get forms' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "forms", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["forms"]);
+      });
+    }
+
+    get scripts() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scripts' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "scripts", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["scripts"]);
+      });
+    }
+
+    get currentScript() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get currentScript' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["currentScript"]);
+    }
+
+    get defaultView() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get defaultView' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["defaultView"]);
+    }
+
+    get onreadystatechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onreadystatechange"]);
+    }
+
+    set onreadystatechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onreadystatechange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onreadystatechange"] = V;
+    }
+
+    get anchors() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get anchors' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "anchors", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["anchors"]);
+      });
+    }
+
+    get applets() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get applets' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "applets", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["applets"]);
+      });
+    }
+
+    get styleSheets() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get styleSheets' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "styleSheets", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["styleSheets"]);
+      });
+    }
+
+    get hidden() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hidden' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["hidden"];
+    }
+
+    get visibilityState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get visibilityState' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["visibilityState"]);
+    }
+
+    get onvisibilitychange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onvisibilitychange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onvisibilitychange"]);
+    }
+
+    set onvisibilitychange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onvisibilitychange' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onvisibilitychange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onvisibilitychange"] = V;
+    }
+
+    get onabort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onabort' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onabort"]);
+    }
+
+    set onabort(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onabort' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onabort' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onabort"] = V;
+    }
+
+    get onauxclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onauxclick' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onauxclick"]);
+    }
+
+    set onauxclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onauxclick' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onauxclick' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onauxclick"] = V;
+    }
+
+    get onblur() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onblur' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onblur"]);
+    }
+
+    set onblur(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onblur' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onblur' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onblur"] = V;
+    }
+
+    get oncancel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncancel' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncancel"]);
+    }
+
+    set oncancel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncancel' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncancel' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncancel"] = V;
+    }
+
+    get oncanplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncanplay' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncanplay"]);
+    }
+
+    set oncanplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncanplay' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncanplay' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncanplay"] = V;
+    }
+
+    get oncanplaythrough() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncanplaythrough' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncanplaythrough"]);
+    }
+
+    set oncanplaythrough(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncanplaythrough' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncanplaythrough' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncanplaythrough"] = V;
+    }
+
+    get onchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onchange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onchange"]);
+    }
+
+    set onchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onchange' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onchange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onchange"] = V;
+    }
+
+    get onclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclick' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclick"]);
+    }
+
+    set onclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclick' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclick' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclick"] = V;
+    }
+
+    get onclose() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclose' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclose"]);
+    }
+
+    set onclose(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclose' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclose' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclose"] = V;
+    }
+
+    get oncontextmenu() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncontextmenu' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncontextmenu"]);
+    }
+
+    set oncontextmenu(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncontextmenu' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncontextmenu' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncontextmenu"] = V;
+    }
+
+    get oncuechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncuechange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncuechange"]);
+    }
+
+    set oncuechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncuechange' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncuechange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncuechange"] = V;
+    }
+
+    get ondblclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondblclick' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondblclick"]);
+    }
+
+    set ondblclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondblclick' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondblclick' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondblclick"] = V;
+    }
+
+    get ondrag() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondrag' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondrag"]);
+    }
+
+    set ondrag(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondrag' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondrag' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondrag"] = V;
+    }
+
+    get ondragend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragend' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragend"]);
+    }
+
+    set ondragend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragend' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragend' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragend"] = V;
+    }
+
+    get ondragenter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragenter' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragenter"]);
+    }
+
+    set ondragenter(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragenter' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragenter' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragenter"] = V;
+    }
+
+    get ondragleave() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragleave' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragleave"]);
+    }
+
+    set ondragleave(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragleave' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragleave' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragleave"] = V;
+    }
+
+    get ondragover() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragover' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragover"]);
+    }
+
+    set ondragover(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragover' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragover' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragover"] = V;
+    }
+
+    get ondragstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragstart' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragstart"]);
+    }
+
+    set ondragstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragstart' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragstart' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragstart"] = V;
+    }
+
+    get ondrop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondrop' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondrop"]);
+    }
+
+    set ondrop(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondrop' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondrop' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondrop"] = V;
+    }
+
+    get ondurationchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondurationchange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondurationchange"]);
+    }
+
+    set ondurationchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondurationchange' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondurationchange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondurationchange"] = V;
+    }
+
+    get onemptied() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onemptied' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onemptied"]);
+    }
+
+    set onemptied(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onemptied' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onemptied' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onemptied"] = V;
+    }
+
+    get onended() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onended' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onended"]);
+    }
+
+    set onended(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onended' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onended' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onended"] = V;
+    }
+
+    get onerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onerror' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onerror"]);
+    }
+
+    set onerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onerror' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnErrorEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onerror"] = V;
+    }
+
+    get onfocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onfocus' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onfocus"]);
+    }
+
+    set onfocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onfocus' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onfocus' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onfocus"] = V;
+    }
+
+    get oninput() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oninput' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oninput"]);
+    }
+
+    set oninput(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oninput' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oninput' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oninput"] = V;
+    }
+
+    get oninvalid() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oninvalid' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oninvalid"]);
+    }
+
+    set oninvalid(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oninvalid' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oninvalid' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["oninvalid"] = V;
+    }
+
+    get onkeydown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeydown' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeydown"]);
+    }
+
+    set onkeydown(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeydown' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeydown' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeydown"] = V;
+    }
+
+    get onkeypress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeypress' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeypress"]);
+    }
+
+    set onkeypress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeypress' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeypress' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeypress"] = V;
+    }
+
+    get onkeyup() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeyup' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeyup"]);
+    }
+
+    set onkeyup(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeyup' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeyup' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeyup"] = V;
+    }
+
+    get onload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onload' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onload"]);
+    }
+
+    set onload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onload' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onload' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onload"] = V;
+    }
+
+    get onloadeddata() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadeddata' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadeddata"]);
+    }
+
+    set onloadeddata(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadeddata' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadeddata' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadeddata"] = V;
+    }
+
+    get onloadedmetadata() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadedmetadata' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadedmetadata"]);
+    }
+
+    set onloadedmetadata(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadedmetadata' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadedmetadata' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadedmetadata"] = V;
+    }
+
+    get onloadend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadend' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadend"]);
+    }
+
+    set onloadend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadend' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadend' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadend"] = V;
+    }
+
+    get onloadstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadstart' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadstart"]);
+    }
+
+    set onloadstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadstart' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadstart' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadstart"] = V;
+    }
+
+    get onmousedown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmousedown' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmousedown"]);
+    }
+
+    set onmousedown(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmousedown' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmousedown' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmousedown"] = V;
+    }
+
+    get onmouseenter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseenter"]);
+    }
+
+    set onmouseenter(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseenter' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseenter"] = V;
+    }
+
+    get onmouseleave() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseleave"]);
+    }
+
+    set onmouseleave(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseleave' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseleave"] = V;
+    }
+
+    get onmousemove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmousemove' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmousemove"]);
+    }
+
+    set onmousemove(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmousemove' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmousemove' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmousemove"] = V;
+    }
+
+    get onmouseout() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseout' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseout"]);
+    }
+
+    set onmouseout(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseout' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseout' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseout"] = V;
+    }
+
+    get onmouseover() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseover' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseover"]);
+    }
+
+    set onmouseover(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseover' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseover' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseover"] = V;
+    }
+
+    get onmouseup() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseup' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseup"]);
+    }
+
+    set onmouseup(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseup' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseup' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseup"] = V;
+    }
+
+    get onwheel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onwheel' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onwheel"]);
+    }
+
+    set onwheel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onwheel' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onwheel' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onwheel"] = V;
+    }
+
+    get onpause() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpause' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpause"]);
+    }
+
+    set onpause(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpause' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpause' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpause"] = V;
+    }
+
+    get onplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onplay' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onplay"]);
+    }
+
+    set onplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onplay' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onplay' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onplay"] = V;
+    }
+
+    get onplaying() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onplaying' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onplaying"]);
+    }
+
+    set onplaying(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onplaying' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onplaying' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onplaying"] = V;
+    }
+
+    get onprogress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onprogress' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onprogress"]);
+    }
+
+    set onprogress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onprogress' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onprogress' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onprogress"] = V;
+    }
+
+    get onratechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onratechange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onratechange"]);
+    }
+
+    set onratechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onratechange' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onratechange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onratechange"] = V;
+    }
+
+    get onreset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onreset' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onreset"]);
+    }
+
+    set onreset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onreset' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onreset' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onreset"] = V;
+    }
+
+    get onresize() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onresize' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onresize"]);
+    }
+
+    set onresize(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onresize' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onresize' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onresize"] = V;
+    }
+
+    get onscroll() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onscroll' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onscroll"]);
+    }
+
+    set onscroll(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onscroll' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onscroll' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onscroll"] = V;
+    }
+
+    get onsecuritypolicyviolation() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onsecuritypolicyviolation' called on an object that is not a valid instance of Document."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsecuritypolicyviolation"]);
+    }
+
+    set onsecuritypolicyviolation(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onsecuritypolicyviolation' called on an object that is not a valid instance of Document."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsecuritypolicyviolation' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsecuritypolicyviolation"] = V;
+    }
+
+    get onseeked() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onseeked' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onseeked"]);
+    }
+
+    set onseeked(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onseeked' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onseeked' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onseeked"] = V;
+    }
+
+    get onseeking() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onseeking' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onseeking"]);
+    }
+
+    set onseeking(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onseeking' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onseeking' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onseeking"] = V;
+    }
+
+    get onselect() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onselect' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onselect"]);
+    }
+
+    set onselect(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onselect' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onselect' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onselect"] = V;
+    }
+
+    get onstalled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onstalled' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onstalled"]);
+    }
+
+    set onstalled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onstalled' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onstalled' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onstalled"] = V;
+    }
+
+    get onsubmit() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onsubmit' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsubmit"]);
+    }
+
+    set onsubmit(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onsubmit' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsubmit' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsubmit"] = V;
+    }
+
+    get onsuspend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onsuspend' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsuspend"]);
+    }
+
+    set onsuspend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onsuspend' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsuspend' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsuspend"] = V;
+    }
+
+    get ontimeupdate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ontimeupdate' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontimeupdate"]);
+    }
+
+    set ontimeupdate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ontimeupdate' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontimeupdate' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontimeupdate"] = V;
+    }
+
+    get ontoggle() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ontoggle' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontoggle"]);
+    }
+
+    set ontoggle(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ontoggle' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontoggle' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontoggle"] = V;
+    }
+
+    get onvolumechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onvolumechange' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onvolumechange"]);
+    }
+
+    set onvolumechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onvolumechange' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onvolumechange' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onvolumechange"] = V;
+    }
+
+    get onwaiting() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onwaiting' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onwaiting"]);
+    }
+
+    set onwaiting(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onwaiting' called on an object that is not a valid instance of Document.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onwaiting' property on 'Document': The provided value"
+        });
+      }
+      esValue[implSymbol]["onwaiting"] = V;
+    }
+
+    get activeElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get activeElement' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["activeElement"]);
+    }
+
+    get children() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get children' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.getSameObject(this, "children", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["children"]);
+      });
+    }
+
+    get firstElementChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get firstElementChild' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["firstElementChild"]);
+    }
+
+    get lastElementChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lastElementChild' called on an object that is not a valid instance of Document.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["lastElementChild"]);
+    }
+
+    get childElementCount() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get childElementCount' called on an object that is not a valid instance of Document.");
+      }
+
+      return esValue[implSymbol]["childElementCount"];
+    }
+  }
+  Object.defineProperties(Document.prototype, {
+    getElementsByTagName: { enumerable: true },
+    getElementsByTagNameNS: { enumerable: true },
+    getElementsByClassName: { enumerable: true },
+    createElement: { enumerable: true },
+    createElementNS: { enumerable: true },
+    createDocumentFragment: { enumerable: true },
+    createTextNode: { enumerable: true },
+    createCDATASection: { enumerable: true },
+    createComment: { enumerable: true },
+    createProcessingInstruction: { enumerable: true },
+    importNode: { enumerable: true },
+    adoptNode: { enumerable: true },
+    createAttribute: { enumerable: true },
+    createAttributeNS: { enumerable: true },
+    createEvent: { enumerable: true },
+    createRange: { enumerable: true },
+    createNodeIterator: { enumerable: true },
+    createTreeWalker: { enumerable: true },
+    getElementsByName: { enumerable: true },
+    open: { enumerable: true },
+    close: { enumerable: true },
+    write: { enumerable: true },
+    writeln: { enumerable: true },
+    hasFocus: { enumerable: true },
+    clear: { enumerable: true },
+    captureEvents: { enumerable: true },
+    releaseEvents: { enumerable: true },
+    getSelection: { enumerable: true },
+    getElementById: { enumerable: true },
+    prepend: { enumerable: true },
+    append: { enumerable: true },
+    replaceChildren: { enumerable: true },
+    querySelector: { enumerable: true },
+    querySelectorAll: { enumerable: true },
+    implementation: { enumerable: true },
+    URL: { enumerable: true },
+    documentURI: { enumerable: true },
+    compatMode: { enumerable: true },
+    characterSet: { enumerable: true },
+    charset: { enumerable: true },
+    inputEncoding: { enumerable: true },
+    contentType: { enumerable: true },
+    doctype: { enumerable: true },
+    documentElement: { enumerable: true },
+    referrer: { enumerable: true },
+    cookie: { enumerable: true },
+    lastModified: { enumerable: true },
+    readyState: { enumerable: true },
+    title: { enumerable: true },
+    dir: { enumerable: true },
+    body: { enumerable: true },
+    head: { enumerable: true },
+    images: { enumerable: true },
+    embeds: { enumerable: true },
+    plugins: { enumerable: true },
+    links: { enumerable: true },
+    forms: { enumerable: true },
+    scripts: { enumerable: true },
+    currentScript: { enumerable: true },
+    defaultView: { enumerable: true },
+    onreadystatechange: { enumerable: true },
+    anchors: { enumerable: true },
+    applets: { enumerable: true },
+    styleSheets: { enumerable: true },
+    hidden: { enumerable: true },
+    visibilityState: { enumerable: true },
+    onvisibilitychange: { enumerable: true },
+    onabort: { enumerable: true },
+    onauxclick: { enumerable: true },
+    onblur: { enumerable: true },
+    oncancel: { enumerable: true },
+    oncanplay: { enumerable: true },
+    oncanplaythrough: { enumerable: true },
+    onchange: { enumerable: true },
+    onclick: { enumerable: true },
+    onclose: { enumerable: true },
+    oncontextmenu: { enumerable: true },
+    oncuechange: { enumerable: true },
+    ondblclick: { enumerable: true },
+    ondrag: { enumerable: true },
+    ondragend: { enumerable: true },
+    ondragenter: { enumerable: true },
+    ondragleave: { enumerable: true },
+    ondragover: { enumerable: true },
+    ondragstart: { enumerable: true },
+    ondrop: { enumerable: true },
+    ondurationchange: { enumerable: true },
+    onemptied: { enumerable: true },
+    onended: { enumerable: true },
+    onerror: { enumerable: true },
+    onfocus: { enumerable: true },
+    oninput: { enumerable: true },
+    oninvalid: { enumerable: true },
+    onkeydown: { enumerable: true },
+    onkeypress: { enumerable: true },
+    onkeyup: { enumerable: true },
+    onload: { enumerable: true },
+    onloadeddata: { enumerable: true },
+    onloadedmetadata: { enumerable: true },
+    onloadend: { enumerable: true },
+    onloadstart: { enumerable: true },
+    onmousedown: { enumerable: true },
+    onmouseenter: { enumerable: true },
+    onmouseleave: { enumerable: true },
+    onmousemove: { enumerable: true },
+    onmouseout: { enumerable: true },
+    onmouseover: { enumerable: true },
+    onmouseup: { enumerable: true },
+    onwheel: { enumerable: true },
+    onpause: { enumerable: true },
+    onplay: { enumerable: true },
+    onplaying: { enumerable: true },
+    onprogress: { enumerable: true },
+    onratechange: { enumerable: true },
+    onreset: { enumerable: true },
+    onresize: { enumerable: true },
+    onscroll: { enumerable: true },
+    onsecuritypolicyviolation: { enumerable: true },
+    onseeked: { enumerable: true },
+    onseeking: { enumerable: true },
+    onselect: { enumerable: true },
+    onstalled: { enumerable: true },
+    onsubmit: { enumerable: true },
+    onsuspend: { enumerable: true },
+    ontimeupdate: { enumerable: true },
+    ontoggle: { enumerable: true },
+    onvolumechange: { enumerable: true },
+    onwaiting: { enumerable: true },
+    activeElement: { enumerable: true },
+    children: { enumerable: true },
+    firstElementChild: { enumerable: true },
+    lastElementChild: { enumerable: true },
+    childElementCount: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Document", configurable: true },
+    [Symbol.unscopables]: {
+      value: { prepend: true, append: true, replaceChildren: true, __proto__: null },
+      configurable: true
+    }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Document;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Document
+  });
+};
+
+const Impl = require("../nodes/Document-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentFragment.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentFragment.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentFragment.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,325 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "DocumentFragment";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'DocumentFragment'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["DocumentFragment"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor DocumentFragment is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Node._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Node === undefined) {
+    throw new Error("Internal error: attempting to evaluate DocumentFragment before Node");
+  }
+  class DocumentFragment extends globalObject.Node {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    getElementById(elementId) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementById' called on an object that is not a valid instance of DocumentFragment.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementById' on 'DocumentFragment': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementById' on 'DocumentFragment': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementById(...args));
+    }
+
+    prepend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'prepend' called on an object that is not a valid instance of DocumentFragment.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'prepend' on 'DocumentFragment': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].prepend(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    append() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'append' called on an object that is not a valid instance of DocumentFragment.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'append' on 'DocumentFragment': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].append(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceChildren() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceChildren' called on an object that is not a valid instance of DocumentFragment.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'replaceChildren' on 'DocumentFragment': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].replaceChildren(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    querySelector(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'querySelector' called on an object that is not a valid instance of DocumentFragment.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'querySelector' on 'DocumentFragment': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'querySelector' on 'DocumentFragment': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].querySelector(...args));
+    }
+
+    querySelectorAll(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'querySelectorAll' called on an object that is not a valid instance of DocumentFragment.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'querySelectorAll' on 'DocumentFragment': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'querySelectorAll' on 'DocumentFragment': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].querySelectorAll(...args));
+    }
+
+    get children() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get children' called on an object that is not a valid instance of DocumentFragment.");
+      }
+
+      return utils.getSameObject(this, "children", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["children"]);
+      });
+    }
+
+    get firstElementChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get firstElementChild' called on an object that is not a valid instance of DocumentFragment."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["firstElementChild"]);
+    }
+
+    get lastElementChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get lastElementChild' called on an object that is not a valid instance of DocumentFragment."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["lastElementChild"]);
+    }
+
+    get childElementCount() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get childElementCount' called on an object that is not a valid instance of DocumentFragment."
+        );
+      }
+
+      return esValue[implSymbol]["childElementCount"];
+    }
+  }
+  Object.defineProperties(DocumentFragment.prototype, {
+    getElementById: { enumerable: true },
+    prepend: { enumerable: true },
+    append: { enumerable: true },
+    replaceChildren: { enumerable: true },
+    querySelector: { enumerable: true },
+    querySelectorAll: { enumerable: true },
+    children: { enumerable: true },
+    firstElementChild: { enumerable: true },
+    lastElementChild: { enumerable: true },
+    childElementCount: { enumerable: true },
+    [Symbol.toStringTag]: { value: "DocumentFragment", configurable: true },
+    [Symbol.unscopables]: {
+      value: { prepend: true, append: true, replaceChildren: true, __proto__: null },
+      configurable: true
+    }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = DocumentFragment;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: DocumentFragment
+  });
+};
+
+const Impl = require("../nodes/DocumentFragment-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentReadyState.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentReadyState.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentReadyState.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["loading", "interactive", "complete"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for DocumentReadyState`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentType.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/DocumentType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,246 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "DocumentType";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'DocumentType'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["DocumentType"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor DocumentType is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Node._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Node === undefined) {
+    throw new Error("Internal error: attempting to evaluate DocumentType before Node");
+  }
+  class DocumentType extends globalObject.Node {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    before() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'before' called on an object that is not a valid instance of DocumentType.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'before' on 'DocumentType': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].before(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    after() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'after' called on an object that is not a valid instance of DocumentType.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'after' on 'DocumentType': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].after(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceWith() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceWith' called on an object that is not a valid instance of DocumentType.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'replaceWith' on 'DocumentType': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].replaceWith(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    remove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'remove' called on an object that is not a valid instance of DocumentType.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].remove();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of DocumentType.");
+      }
+
+      return esValue[implSymbol]["name"];
+    }
+
+    get publicId() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get publicId' called on an object that is not a valid instance of DocumentType.");
+      }
+
+      return esValue[implSymbol]["publicId"];
+    }
+
+    get systemId() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get systemId' called on an object that is not a valid instance of DocumentType.");
+      }
+
+      return esValue[implSymbol]["systemId"];
+    }
+  }
+  Object.defineProperties(DocumentType.prototype, {
+    before: { enumerable: true },
+    after: { enumerable: true },
+    replaceWith: { enumerable: true },
+    remove: { enumerable: true },
+    name: { enumerable: true },
+    publicId: { enumerable: true },
+    systemId: { enumerable: true },
+    [Symbol.toStringTag]: { value: "DocumentType", configurable: true },
+    [Symbol.unscopables]: {
+      value: { before: true, after: true, replaceWith: true, remove: true, __proto__: null },
+      configurable: true
+    }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = DocumentType;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: DocumentType
+  });
+};
+
+const Impl = require("../nodes/DocumentType-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Element.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Element.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Element.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1609 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const Attr = require("./Attr.js");
+const ShadowRootInit = require("./ShadowRootInit.js");
+const Node = require("./Node.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Element";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Element'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Element"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Element is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Node._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Node === undefined) {
+    throw new Error("Internal error: attempting to evaluate Element before Node");
+  }
+  class Element extends globalObject.Node {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    hasAttributes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'hasAttributes' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol].hasAttributes();
+    }
+
+    getAttributeNames() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getAttributeNames' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].getAttributeNames());
+    }
+
+    getAttribute(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getAttribute' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getAttribute' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getAttribute' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getAttribute(...args);
+    }
+
+    getAttributeNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getAttributeNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'getAttributeNS' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'getAttributeNS' on 'Element': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getAttributeNS' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getAttributeNS(...args);
+    }
+
+    setAttribute(qualifiedName, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setAttribute' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setAttribute' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setAttribute' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setAttribute' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].setAttribute(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    setAttributeNS(namespace, qualifiedName, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setAttributeNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 3) {
+        throw new TypeError(
+          "Failed to execute 'setAttributeNS' on 'Element': 3 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'setAttributeNS' on 'Element': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setAttributeNS' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setAttributeNS' on 'Element': parameter 3"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].setAttributeNS(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    removeAttribute(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeAttribute' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeAttribute' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'removeAttribute' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].removeAttribute(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    removeAttributeNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeAttributeNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'removeAttributeNS' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'removeAttributeNS' on 'Element': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'removeAttributeNS' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].removeAttributeNS(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    toggleAttribute(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toggleAttribute' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'toggleAttribute' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'toggleAttribute' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'toggleAttribute' on 'Element': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].toggleAttribute(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    hasAttribute(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'hasAttribute' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'hasAttribute' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'hasAttribute' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].hasAttribute(...args);
+    }
+
+    hasAttributeNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'hasAttributeNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'hasAttributeNS' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'hasAttributeNS' on 'Element': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'hasAttributeNS' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].hasAttributeNS(...args);
+    }
+
+    getAttributeNode(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getAttributeNode' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getAttributeNode' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getAttributeNode' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getAttributeNode(...args));
+    }
+
+    getAttributeNodeNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getAttributeNodeNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'getAttributeNodeNS' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'getAttributeNodeNS' on 'Element': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getAttributeNodeNS' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getAttributeNodeNS(...args));
+    }
+
+    setAttributeNode(attr) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setAttributeNode' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setAttributeNode' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Attr.convert(curArg, { context: "Failed to execute 'setAttributeNode' on 'Element': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].setAttributeNode(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    setAttributeNodeNS(attr) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setAttributeNodeNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setAttributeNodeNS' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Attr.convert(curArg, { context: "Failed to execute 'setAttributeNodeNS' on 'Element': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].setAttributeNodeNS(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    removeAttributeNode(attr) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeAttributeNode' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeAttributeNode' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Attr.convert(curArg, { context: "Failed to execute 'removeAttributeNode' on 'Element': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].removeAttributeNode(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    attachShadow(init) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'attachShadow' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'attachShadow' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = ShadowRootInit.convert(curArg, {
+          context: "Failed to execute 'attachShadow' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].attachShadow(...args));
+    }
+
+    closest(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'closest' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'closest' on 'Element': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'closest' on 'Element': parameter 1" });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].closest(...args));
+    }
+
+    matches(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'matches' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'matches' on 'Element': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'matches' on 'Element': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].matches(...args);
+    }
+
+    webkitMatchesSelector(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'webkitMatchesSelector' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'webkitMatchesSelector' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'webkitMatchesSelector' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].webkitMatchesSelector(...args);
+    }
+
+    getElementsByTagName(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByTagName' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByTagName' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByTagName' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByTagName(...args));
+    }
+
+    getElementsByTagNameNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByTagNameNS' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByTagNameNS' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'getElementsByTagNameNS' on 'Element': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByTagNameNS' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByTagNameNS(...args));
+    }
+
+    getElementsByClassName(classNames) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementsByClassName' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementsByClassName' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementsByClassName' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementsByClassName(...args));
+    }
+
+    insertAdjacentElement(where, element) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertAdjacentElement' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'insertAdjacentElement' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertAdjacentElement' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = exports.convert(curArg, {
+          context: "Failed to execute 'insertAdjacentElement' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].insertAdjacentElement(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    insertAdjacentText(where, data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertAdjacentText' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'insertAdjacentText' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertAdjacentText' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertAdjacentText' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].insertAdjacentText(...args);
+    }
+
+    insertAdjacentHTML(position, text) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertAdjacentHTML' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'insertAdjacentHTML' on 'Element': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertAdjacentHTML' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertAdjacentHTML' on 'Element': parameter 2"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].insertAdjacentHTML(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    getClientRects() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getClientRects' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].getClientRects());
+    }
+
+    getBoundingClientRect() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getBoundingClientRect' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].getBoundingClientRect());
+    }
+
+    before() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'before' called on an object that is not a valid instance of Element.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'before' on 'Element': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].before(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    after() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'after' called on an object that is not a valid instance of Element.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'after' on 'Element': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].after(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceWith() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceWith' called on an object that is not a valid instance of Element.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'replaceWith' on 'Element': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].replaceWith(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    remove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'remove' called on an object that is not a valid instance of Element.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].remove();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    prepend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'prepend' called on an object that is not a valid instance of Element.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'prepend' on 'Element': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].prepend(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    append() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'append' called on an object that is not a valid instance of Element.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'append' on 'Element': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].append(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceChildren() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceChildren' called on an object that is not a valid instance of Element.");
+      }
+      const args = [];
+      for (let i = 0; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        if (Node.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'replaceChildren' on 'Element': parameter " + (i + 1)
+          });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].replaceChildren(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    querySelector(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'querySelector' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'querySelector' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'querySelector' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].querySelector(...args));
+    }
+
+    querySelectorAll(selectors) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'querySelectorAll' called on an object that is not a valid instance of Element.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'querySelectorAll' on 'Element': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'querySelectorAll' on 'Element': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].querySelectorAll(...args));
+    }
+
+    get namespaceURI() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get namespaceURI' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["namespaceURI"];
+    }
+
+    get prefix() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get prefix' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["prefix"];
+    }
+
+    get localName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get localName' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["localName"];
+    }
+
+    get tagName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tagName' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["tagName"];
+    }
+
+    get id() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get id' called on an object that is not a valid instance of Element.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "id");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set id(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set id' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["DOMString"](V, { context: "Failed to set the 'id' property on 'Element': The provided value" });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "id", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get className() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get className' called on an object that is not a valid instance of Element.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "class");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set className(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set className' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'className' property on 'Element': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "class", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get classList() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get classList' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.getSameObject(this, "classList", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["classList"]);
+      });
+    }
+
+    set classList(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set classList' called on an object that is not a valid instance of Element.");
+      }
+
+      const Q = esValue["classList"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'classList' is not an object");
+      }
+      Reflect.set(Q, "value", V);
+    }
+
+    get slot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get slot' called on an object that is not a valid instance of Element.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "slot");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set slot(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set slot' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'slot' property on 'Element': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "slot", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get attributes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get attributes' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.getSameObject(this, "attributes", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["attributes"]);
+      });
+    }
+
+    get shadowRoot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get shadowRoot' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["shadowRoot"]);
+    }
+
+    get outerHTML() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get outerHTML' called on an object that is not a valid instance of Element.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["outerHTML"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set outerHTML(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set outerHTML' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'outerHTML' property on 'Element': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["outerHTML"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get scrollTop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scrollTop' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["scrollTop"];
+    }
+
+    set scrollTop(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set scrollTop' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["unrestricted double"](V, {
+        context: "Failed to set the 'scrollTop' property on 'Element': The provided value"
+      });
+
+      esValue[implSymbol]["scrollTop"] = V;
+    }
+
+    get scrollLeft() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scrollLeft' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["scrollLeft"];
+    }
+
+    set scrollLeft(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set scrollLeft' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["unrestricted double"](V, {
+        context: "Failed to set the 'scrollLeft' property on 'Element': The provided value"
+      });
+
+      esValue[implSymbol]["scrollLeft"] = V;
+    }
+
+    get scrollWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scrollWidth' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["scrollWidth"];
+    }
+
+    get scrollHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scrollHeight' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["scrollHeight"];
+    }
+
+    get clientTop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clientTop' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["clientTop"];
+    }
+
+    get clientLeft() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clientLeft' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["clientLeft"];
+    }
+
+    get clientWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clientWidth' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["clientWidth"];
+    }
+
+    get clientHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clientHeight' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["clientHeight"];
+    }
+
+    get innerHTML() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get innerHTML' called on an object that is not a valid instance of Element.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["innerHTML"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set innerHTML(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set innerHTML' called on an object that is not a valid instance of Element.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'innerHTML' property on 'Element': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["innerHTML"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get previousElementSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get previousElementSibling' called on an object that is not a valid instance of Element."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["previousElementSibling"]);
+    }
+
+    get nextElementSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nextElementSibling' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["nextElementSibling"]);
+    }
+
+    get children() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get children' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.getSameObject(this, "children", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["children"]);
+      });
+    }
+
+    get firstElementChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get firstElementChild' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["firstElementChild"]);
+    }
+
+    get lastElementChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lastElementChild' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["lastElementChild"]);
+    }
+
+    get childElementCount() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get childElementCount' called on an object that is not a valid instance of Element.");
+      }
+
+      return esValue[implSymbol]["childElementCount"];
+    }
+
+    get assignedSlot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get assignedSlot' called on an object that is not a valid instance of Element.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["assignedSlot"]);
+    }
+  }
+  Object.defineProperties(Element.prototype, {
+    hasAttributes: { enumerable: true },
+    getAttributeNames: { enumerable: true },
+    getAttribute: { enumerable: true },
+    getAttributeNS: { enumerable: true },
+    setAttribute: { enumerable: true },
+    setAttributeNS: { enumerable: true },
+    removeAttribute: { enumerable: true },
+    removeAttributeNS: { enumerable: true },
+    toggleAttribute: { enumerable: true },
+    hasAttribute: { enumerable: true },
+    hasAttributeNS: { enumerable: true },
+    getAttributeNode: { enumerable: true },
+    getAttributeNodeNS: { enumerable: true },
+    setAttributeNode: { enumerable: true },
+    setAttributeNodeNS: { enumerable: true },
+    removeAttributeNode: { enumerable: true },
+    attachShadow: { enumerable: true },
+    closest: { enumerable: true },
+    matches: { enumerable: true },
+    webkitMatchesSelector: { enumerable: true },
+    getElementsByTagName: { enumerable: true },
+    getElementsByTagNameNS: { enumerable: true },
+    getElementsByClassName: { enumerable: true },
+    insertAdjacentElement: { enumerable: true },
+    insertAdjacentText: { enumerable: true },
+    insertAdjacentHTML: { enumerable: true },
+    getClientRects: { enumerable: true },
+    getBoundingClientRect: { enumerable: true },
+    before: { enumerable: true },
+    after: { enumerable: true },
+    replaceWith: { enumerable: true },
+    remove: { enumerable: true },
+    prepend: { enumerable: true },
+    append: { enumerable: true },
+    replaceChildren: { enumerable: true },
+    querySelector: { enumerable: true },
+    querySelectorAll: { enumerable: true },
+    namespaceURI: { enumerable: true },
+    prefix: { enumerable: true },
+    localName: { enumerable: true },
+    tagName: { enumerable: true },
+    id: { enumerable: true },
+    className: { enumerable: true },
+    classList: { enumerable: true },
+    slot: { enumerable: true },
+    attributes: { enumerable: true },
+    shadowRoot: { enumerable: true },
+    outerHTML: { enumerable: true },
+    scrollTop: { enumerable: true },
+    scrollLeft: { enumerable: true },
+    scrollWidth: { enumerable: true },
+    scrollHeight: { enumerable: true },
+    clientTop: { enumerable: true },
+    clientLeft: { enumerable: true },
+    clientWidth: { enumerable: true },
+    clientHeight: { enumerable: true },
+    innerHTML: { enumerable: true },
+    previousElementSibling: { enumerable: true },
+    nextElementSibling: { enumerable: true },
+    children: { enumerable: true },
+    firstElementChild: { enumerable: true },
+    lastElementChild: { enumerable: true },
+    childElementCount: { enumerable: true },
+    assignedSlot: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Element", configurable: true },
+    [Symbol.unscopables]: {
+      value: {
+        slot: true,
+        before: true,
+        after: true,
+        replaceWith: true,
+        remove: true,
+        prepend: true,
+        append: true,
+        replaceChildren: true,
+        __proto__: null
+      },
+      configurable: true
+    }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Element;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Element
+  });
+};
+
+const Impl = require("../nodes/Element-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ElementCreationOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ElementCreationOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ElementCreationOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "is";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'is' that" });
+
+      ret[key] = value;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ElementDefinitionOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ElementDefinitionOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ElementDefinitionOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "extends";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'extends' that" });
+
+      ret[key] = value;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EndingType.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EndingType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EndingType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["transparent", "native"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for EndingType`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ErrorEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ErrorEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ErrorEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,186 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ErrorEventInit = require("./ErrorEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "ErrorEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'ErrorEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["ErrorEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor ErrorEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate ErrorEvent before Event");
+  }
+  class ErrorEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'ErrorEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'ErrorEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = ErrorEventInit.convert(curArg, { context: "Failed to construct 'ErrorEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get message() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get message' called on an object that is not a valid instance of ErrorEvent.");
+      }
+
+      return esValue[implSymbol]["message"];
+    }
+
+    get filename() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get filename' called on an object that is not a valid instance of ErrorEvent.");
+      }
+
+      return esValue[implSymbol]["filename"];
+    }
+
+    get lineno() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lineno' called on an object that is not a valid instance of ErrorEvent.");
+      }
+
+      return esValue[implSymbol]["lineno"];
+    }
+
+    get colno() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get colno' called on an object that is not a valid instance of ErrorEvent.");
+      }
+
+      return esValue[implSymbol]["colno"];
+    }
+
+    get error() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get error' called on an object that is not a valid instance of ErrorEvent.");
+      }
+
+      return esValue[implSymbol]["error"];
+    }
+  }
+  Object.defineProperties(ErrorEvent.prototype, {
+    message: { enumerable: true },
+    filename: { enumerable: true },
+    lineno: { enumerable: true },
+    colno: { enumerable: true },
+    error: { enumerable: true },
+    [Symbol.toStringTag]: { value: "ErrorEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = ErrorEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: ErrorEvent
+  });
+};
+
+const Impl = require("../events/ErrorEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ErrorEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ErrorEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ErrorEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,80 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "colno";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'colno' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "error";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["any"](value, { context: context + " has member 'error' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "filename";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["USVString"](value, { context: context + " has member 'filename' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "lineno";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'lineno' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "message";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'message' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Event.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Event.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Event.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,390 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Event";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Event'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Event"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Event is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Object.defineProperties(
+    wrapper,
+    Object.getOwnPropertyDescriptors({
+      get isTrusted() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get isTrusted' called on an object that is not a valid instance of Event.");
+        }
+
+        return esValue[implSymbol]["isTrusted"];
+      }
+    })
+  );
+
+  Object.defineProperties(wrapper, { isTrusted: { configurable: false } });
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker", "AudioWorklet"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'Event': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'Event': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = EventInit.convert(curArg, { context: "Failed to construct 'Event': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    composedPath() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'composedPath' called on an object that is not a valid instance of Event.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].composedPath());
+    }
+
+    stopPropagation() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'stopPropagation' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol].stopPropagation();
+    }
+
+    stopImmediatePropagation() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'stopImmediatePropagation' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol].stopImmediatePropagation();
+    }
+
+    preventDefault() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'preventDefault' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol].preventDefault();
+    }
+
+    initEvent(type) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initEvent' called on an object that is not a valid instance of Event.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initEvent' on 'Event': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'initEvent' on 'Event': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, { context: "Failed to execute 'initEvent' on 'Event': parameter 2" });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, { context: "Failed to execute 'initEvent' on 'Event': parameter 3" });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initEvent(...args);
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of Event.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["target"]);
+    }
+
+    get srcElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get srcElement' called on an object that is not a valid instance of Event.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["srcElement"]);
+    }
+
+    get currentTarget() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get currentTarget' called on an object that is not a valid instance of Event.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["currentTarget"]);
+    }
+
+    get eventPhase() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get eventPhase' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["eventPhase"];
+    }
+
+    get cancelBubble() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cancelBubble' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["cancelBubble"];
+    }
+
+    set cancelBubble(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cancelBubble' called on an object that is not a valid instance of Event.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'cancelBubble' property on 'Event': The provided value"
+      });
+
+      esValue[implSymbol]["cancelBubble"] = V;
+    }
+
+    get bubbles() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bubbles' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["bubbles"];
+    }
+
+    get cancelable() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cancelable' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["cancelable"];
+    }
+
+    get returnValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get returnValue' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["returnValue"];
+    }
+
+    set returnValue(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set returnValue' called on an object that is not a valid instance of Event.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'returnValue' property on 'Event': The provided value"
+      });
+
+      esValue[implSymbol]["returnValue"] = V;
+    }
+
+    get defaultPrevented() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get defaultPrevented' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["defaultPrevented"];
+    }
+
+    get composed() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get composed' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["composed"];
+    }
+
+    get timeStamp() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get timeStamp' called on an object that is not a valid instance of Event.");
+      }
+
+      return esValue[implSymbol]["timeStamp"];
+    }
+  }
+  Object.defineProperties(Event.prototype, {
+    composedPath: { enumerable: true },
+    stopPropagation: { enumerable: true },
+    stopImmediatePropagation: { enumerable: true },
+    preventDefault: { enumerable: true },
+    initEvent: { enumerable: true },
+    type: { enumerable: true },
+    target: { enumerable: true },
+    srcElement: { enumerable: true },
+    currentTarget: { enumerable: true },
+    eventPhase: { enumerable: true },
+    cancelBubble: { enumerable: true },
+    bubbles: { enumerable: true },
+    cancelable: { enumerable: true },
+    returnValue: { enumerable: true },
+    defaultPrevented: { enumerable: true },
+    composed: { enumerable: true },
+    timeStamp: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Event", configurable: true },
+    NONE: { value: 0, enumerable: true },
+    CAPTURING_PHASE: { value: 1, enumerable: true },
+    AT_TARGET: { value: 2, enumerable: true },
+    BUBBLING_PHASE: { value: 3, enumerable: true }
+  });
+  Object.defineProperties(Event, {
+    NONE: { value: 0, enumerable: true },
+    CAPTURING_PHASE: { value: 1, enumerable: true },
+    AT_TARGET: { value: 2, enumerable: true },
+    BUBBLING_PHASE: { value: 3, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Event;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Event
+  });
+};
+
+const Impl = require("../events/Event-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EventHandlerNonNull.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EventHandlerNonNull.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EventHandlerNonNull.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,40 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  function invokeTheCallbackFunction(event) {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    if (typeof value === "function") {
+      event = utils.tryWrapperForImpl(event);
+
+      callResult = Reflect.apply(value, thisArg, [event]);
+    }
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  }
+
+  invokeTheCallbackFunction.construct = event => {
+    event = utils.tryWrapperForImpl(event);
+
+    let callResult = Reflect.construct(value, [event]);
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "bubbles";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'bubbles' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "cancelable";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'cancelable' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "composed";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'composed' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  if (!utils.isObject(value)) {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  function callTheUserObjectsOperation(event) {
+    let thisArg = utils.tryWrapperForImpl(this);
+    let O = value;
+    let X = O;
+
+    if (typeof O !== "function") {
+      X = O["handleEvent"];
+      if (typeof X !== "function") {
+        throw new TypeError(`${context} does not correctly implement EventListener.`);
+      }
+      thisArg = O;
+    }
+
+    event = utils.tryWrapperForImpl(event);
+
+    let callResult = Reflect.apply(X, thisArg, [event]);
+  }
+
+  callTheUserObjectsOperation[utils.wrapperSymbol] = value;
+  callTheUserObjectsOperation.objectReference = value;
+
+  return callTheUserObjectsOperation;
+};
+
+exports.install = (globalObject, globalNames) => {};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EventListenerOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EventListenerOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EventListenerOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "capture";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'capture' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EventModifierInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EventModifierInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EventModifierInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,188 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const UIEventInit = require("./UIEventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  UIEventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "altKey";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'altKey' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "ctrlKey";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'ctrlKey' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "metaKey";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'metaKey' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierAltGraph";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierAltGraph' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierCapsLock";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierCapsLock' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierFn";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierFn' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierFnLock";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierFnLock' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierHyper";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierHyper' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierNumLock";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierNumLock' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierScrollLock";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierScrollLock' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierSuper";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierSuper' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierSymbol";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierSymbol' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "modifierSymbolLock";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'modifierSymbolLock' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "shiftKey";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'shiftKey' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,252 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventListener = require("./EventListener.js");
+const AddEventListenerOptions = require("./AddEventListenerOptions.js");
+const EventListenerOptions = require("./EventListenerOptions.js");
+const Event = require("./Event.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "EventTarget";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'EventTarget'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["EventTarget"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor EventTarget is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker", "AudioWorklet"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class EventTarget {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    addEventListener(type, callback) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'addEventListener' called on an object that is not a valid instance of EventTarget.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = EventListener.convert(curArg, {
+            context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = AddEventListenerOptions.convert(curArg, {
+              context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3"
+            });
+          } else if (utils.isObject(curArg)) {
+            curArg = AddEventListenerOptions.convert(curArg, {
+              context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3" + " dictionary"
+            });
+          } else if (typeof curArg === "boolean") {
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3"
+            });
+          } else {
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'addEventListener' on 'EventTarget': parameter 3"
+            });
+          }
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].addEventListener(...args);
+    }
+
+    removeEventListener(type, callback) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeEventListener' called on an object that is not a valid instance of EventTarget.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'removeEventListener' on 'EventTarget': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = EventListener.convert(curArg, {
+            context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = EventListenerOptions.convert(curArg, {
+              context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3"
+            });
+          } else if (utils.isObject(curArg)) {
+            curArg = EventListenerOptions.convert(curArg, {
+              context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3" + " dictionary"
+            });
+          } else if (typeof curArg === "boolean") {
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3"
+            });
+          } else {
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'removeEventListener' on 'EventTarget': parameter 3"
+            });
+          }
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].removeEventListener(...args);
+    }
+
+    dispatchEvent(event) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'dispatchEvent' called on an object that is not a valid instance of EventTarget.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'dispatchEvent' on 'EventTarget': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Event.convert(curArg, { context: "Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].dispatchEvent(...args);
+    }
+  }
+  Object.defineProperties(EventTarget.prototype, {
+    addEventListener: { enumerable: true },
+    removeEventListener: { enumerable: true },
+    dispatchEvent: { enumerable: true },
+    [Symbol.toStringTag]: { value: "EventTarget", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = EventTarget;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: EventTarget
+  });
+};
+
+const Impl = require("../events/EventTarget-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/External.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/External.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/External.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,129 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "External";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'External'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["External"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor External is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class External {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    AddSearchProvider() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'AddSearchProvider' called on an object that is not a valid instance of External.");
+      }
+
+      return esValue[implSymbol].AddSearchProvider();
+    }
+
+    IsSearchProviderInstalled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'IsSearchProviderInstalled' called on an object that is not a valid instance of External."
+        );
+      }
+
+      return esValue[implSymbol].IsSearchProviderInstalled();
+    }
+  }
+  Object.defineProperties(External.prototype, {
+    AddSearchProvider: { enumerable: true },
+    IsSearchProviderInstalled: { enumerable: true },
+    [Symbol.toStringTag]: { value: "External", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = External;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: External
+  });
+};
+
+const Impl = require("../window/External-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/File.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/File.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/File.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,176 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Blob = require("./Blob.js");
+const FilePropertyBag = require("./FilePropertyBag.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "File";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'File'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["File"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor File is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Blob._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Blob === undefined) {
+    throw new Error("Internal error: attempting to evaluate File before Blob");
+  }
+  class File extends globalObject.Blob {
+    constructor(fileBits, fileName) {
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to construct 'File': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (!utils.isObject(curArg)) {
+          throw new TypeError("Failed to construct 'File': parameter 1" + " is not an iterable object.");
+        } else {
+          const V = [];
+          const tmp = curArg;
+          for (let nextItem of tmp) {
+            if (Blob.is(nextItem)) {
+              nextItem = utils.implForWrapper(nextItem);
+            } else if (utils.isArrayBuffer(nextItem)) {
+            } else if (ArrayBuffer.isView(nextItem)) {
+            } else {
+              nextItem = conversions["USVString"](nextItem, {
+                context: "Failed to construct 'File': parameter 1" + "'s element"
+              });
+            }
+            V.push(nextItem);
+          }
+          curArg = V;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["USVString"](curArg, { context: "Failed to construct 'File': parameter 2" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        curArg = FilePropertyBag.convert(curArg, { context: "Failed to construct 'File': parameter 3" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of File.");
+      }
+
+      return esValue[implSymbol]["name"];
+    }
+
+    get lastModified() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lastModified' called on an object that is not a valid instance of File.");
+      }
+
+      return esValue[implSymbol]["lastModified"];
+    }
+  }
+  Object.defineProperties(File.prototype, {
+    name: { enumerable: true },
+    lastModified: { enumerable: true },
+    [Symbol.toStringTag]: { value: "File", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = File;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: File
+  });
+};
+
+const Impl = require("../file-api/File-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/FileList.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/FileList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/FileList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,305 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "FileList";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'FileList'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["FileList"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor FileList is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class FileList {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of FileList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'FileList': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'FileList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of FileList.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(FileList.prototype, {
+    item: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "FileList", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = FileList;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: FileList
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../file-api/FileList-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/FilePropertyBag.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/FilePropertyBag.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/FilePropertyBag.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const BlobPropertyBag = require("./BlobPropertyBag.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  BlobPropertyBag._convertInherit(obj, ret, { context });
+
+  {
+    const key = "lastModified";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["long long"](value, { context: context + " has member 'lastModified' that" });
+
+      ret[key] = value;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/FileReader.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/FileReader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/FileReader.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,440 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Blob = require("./Blob.js");
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const EventTarget = require("./EventTarget.js");
+
+const interfaceName = "FileReader";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'FileReader'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["FileReader"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor FileReader is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  EventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.EventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate FileReader before EventTarget");
+  }
+  class FileReader extends globalObject.EventTarget {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    readAsArrayBuffer(blob) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'readAsArrayBuffer' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'readAsArrayBuffer' on 'FileReader': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Blob.convert(curArg, {
+          context: "Failed to execute 'readAsArrayBuffer' on 'FileReader': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].readAsArrayBuffer(...args);
+    }
+
+    readAsBinaryString(blob) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'readAsBinaryString' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'readAsBinaryString' on 'FileReader': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Blob.convert(curArg, {
+          context: "Failed to execute 'readAsBinaryString' on 'FileReader': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].readAsBinaryString(...args);
+    }
+
+    readAsText(blob) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'readAsText' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'readAsText' on 'FileReader': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Blob.convert(curArg, { context: "Failed to execute 'readAsText' on 'FileReader': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'readAsText' on 'FileReader': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].readAsText(...args);
+    }
+
+    readAsDataURL(blob) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'readAsDataURL' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'readAsDataURL' on 'FileReader': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Blob.convert(curArg, { context: "Failed to execute 'readAsDataURL' on 'FileReader': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].readAsDataURL(...args);
+    }
+
+    abort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'abort' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return esValue[implSymbol].abort();
+    }
+
+    get readyState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readyState' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return esValue[implSymbol]["readyState"];
+    }
+
+    get result() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get result' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["result"]);
+    }
+
+    get error() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get error' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["error"]);
+    }
+
+    get onloadstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadstart' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadstart"]);
+    }
+
+    set onloadstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadstart' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadstart' property on 'FileReader': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadstart"] = V;
+    }
+
+    get onprogress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onprogress' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onprogress"]);
+    }
+
+    set onprogress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onprogress' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onprogress' property on 'FileReader': The provided value"
+        });
+      }
+      esValue[implSymbol]["onprogress"] = V;
+    }
+
+    get onload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onload' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onload"]);
+    }
+
+    set onload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onload' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onload' property on 'FileReader': The provided value"
+        });
+      }
+      esValue[implSymbol]["onload"] = V;
+    }
+
+    get onabort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onabort' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onabort"]);
+    }
+
+    set onabort(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onabort' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onabort' property on 'FileReader': The provided value"
+        });
+      }
+      esValue[implSymbol]["onabort"] = V;
+    }
+
+    get onerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onerror' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onerror"]);
+    }
+
+    set onerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onerror' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'FileReader': The provided value"
+        });
+      }
+      esValue[implSymbol]["onerror"] = V;
+    }
+
+    get onloadend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadend' called on an object that is not a valid instance of FileReader.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadend"]);
+    }
+
+    set onloadend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadend' called on an object that is not a valid instance of FileReader.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadend' property on 'FileReader': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadend"] = V;
+    }
+  }
+  Object.defineProperties(FileReader.prototype, {
+    readAsArrayBuffer: { enumerable: true },
+    readAsBinaryString: { enumerable: true },
+    readAsText: { enumerable: true },
+    readAsDataURL: { enumerable: true },
+    abort: { enumerable: true },
+    readyState: { enumerable: true },
+    result: { enumerable: true },
+    error: { enumerable: true },
+    onloadstart: { enumerable: true },
+    onprogress: { enumerable: true },
+    onload: { enumerable: true },
+    onabort: { enumerable: true },
+    onerror: { enumerable: true },
+    onloadend: { enumerable: true },
+    [Symbol.toStringTag]: { value: "FileReader", configurable: true },
+    EMPTY: { value: 0, enumerable: true },
+    LOADING: { value: 1, enumerable: true },
+    DONE: { value: 2, enumerable: true }
+  });
+  Object.defineProperties(FileReader, {
+    EMPTY: { value: 0, enumerable: true },
+    LOADING: { value: 1, enumerable: true },
+    DONE: { value: 2, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = FileReader;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: FileReader
+  });
+};
+
+const Impl = require("../file-api/FileReader-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/FocusEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/FocusEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/FocusEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,142 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const FocusEventInit = require("./FocusEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const UIEvent = require("./UIEvent.js");
+
+const interfaceName = "FocusEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'FocusEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["FocusEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor FocusEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  UIEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.UIEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate FocusEvent before UIEvent");
+  }
+  class FocusEvent extends globalObject.UIEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'FocusEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'FocusEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = FocusEventInit.convert(curArg, { context: "Failed to construct 'FocusEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get relatedTarget() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get relatedTarget' called on an object that is not a valid instance of FocusEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["relatedTarget"]);
+    }
+  }
+  Object.defineProperties(FocusEvent.prototype, {
+    relatedTarget: { enumerable: true },
+    [Symbol.toStringTag]: { value: "FocusEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = FocusEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: FocusEvent
+  });
+};
+
+const Impl = require("../events/FocusEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/FocusEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/FocusEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/FocusEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,36 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventTarget = require("./EventTarget.js");
+const UIEventInit = require("./UIEventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  UIEventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "relatedTarget";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = EventTarget.convert(value, { context: context + " has member 'relatedTarget' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/FormData.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/FormData.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/FormData.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,421 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLFormElement = require("./HTMLFormElement.js");
+const Blob = require("./Blob.js");
+const Function = require("./Function.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "FormData";
+
+const IteratorPrototype = Object.create(utils.IteratorPrototype, {
+  next: {
+    value: function next() {
+      const internal = this && this[utils.iterInternalSymbol];
+      if (!internal) {
+        throw new TypeError("next() called on a value that is not an iterator prototype object");
+      }
+
+      const { target, kind, index } = internal;
+      const values = Array.from(target[implSymbol]);
+      const len = values.length;
+      if (index >= len) {
+        return { value: undefined, done: true };
+      }
+
+      const pair = values[index];
+      internal.index = index + 1;
+      return utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind);
+    },
+    writable: true,
+    enumerable: true,
+    configurable: true
+  },
+  [Symbol.toStringTag]: {
+    value: "FormData Iterator",
+    configurable: true
+  }
+});
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'FormData'.`);
+};
+
+exports.createDefaultIterator = (target, kind) => {
+  const iterator = Object.create(IteratorPrototype);
+  Object.defineProperty(iterator, utils.iterInternalSymbol, {
+    value: { target, kind, index: 0 },
+    configurable: true
+  });
+  return iterator;
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["FormData"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor FormData is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class FormData {
+    constructor() {
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = HTMLFormElement.convert(curArg, { context: "Failed to construct 'FormData': parameter 1" });
+        }
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    append(name, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'append' called on an object that is not a valid instance of FormData.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'append' on 'FormData': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      switch (arguments.length) {
+        case 2:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'append' on 'FormData': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            if (Blob.is(curArg)) {
+              {
+                let curArg = arguments[1];
+                curArg = Blob.convert(curArg, { context: "Failed to execute 'append' on 'FormData': parameter 2" });
+                args.push(curArg);
+              }
+            } else {
+              {
+                let curArg = arguments[1];
+                curArg = conversions["USVString"](curArg, {
+                  context: "Failed to execute 'append' on 'FormData': parameter 2"
+                });
+                args.push(curArg);
+              }
+            }
+          }
+          break;
+        default:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'append' on 'FormData': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = Blob.convert(curArg, { context: "Failed to execute 'append' on 'FormData': parameter 2" });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            if (curArg !== undefined) {
+              curArg = conversions["USVString"](curArg, {
+                context: "Failed to execute 'append' on 'FormData': parameter 3"
+              });
+            }
+            args.push(curArg);
+          }
+      }
+      return esValue[implSymbol].append(...args);
+    }
+
+    delete(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'delete' called on an object that is not a valid instance of FormData.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'delete' on 'FormData': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["USVString"](curArg, { context: "Failed to execute 'delete' on 'FormData': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].delete(...args);
+    }
+
+    get(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get' called on an object that is not a valid instance of FormData.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'get' on 'FormData': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["USVString"](curArg, { context: "Failed to execute 'get' on 'FormData': parameter 1" });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].get(...args));
+    }
+
+    getAll(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getAll' called on an object that is not a valid instance of FormData.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getAll' on 'FormData': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["USVString"](curArg, { context: "Failed to execute 'getAll' on 'FormData': parameter 1" });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getAll(...args));
+    }
+
+    has(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'has' called on an object that is not a valid instance of FormData.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'has' on 'FormData': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["USVString"](curArg, { context: "Failed to execute 'has' on 'FormData': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].has(...args);
+    }
+
+    set(name, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set' called on an object that is not a valid instance of FormData.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'set' on 'FormData': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      switch (arguments.length) {
+        case 2:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'set' on 'FormData': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            if (Blob.is(curArg)) {
+              {
+                let curArg = arguments[1];
+                curArg = Blob.convert(curArg, { context: "Failed to execute 'set' on 'FormData': parameter 2" });
+                args.push(curArg);
+              }
+            } else {
+              {
+                let curArg = arguments[1];
+                curArg = conversions["USVString"](curArg, {
+                  context: "Failed to execute 'set' on 'FormData': parameter 2"
+                });
+                args.push(curArg);
+              }
+            }
+          }
+          break;
+        default:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'set' on 'FormData': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = Blob.convert(curArg, { context: "Failed to execute 'set' on 'FormData': parameter 2" });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            if (curArg !== undefined) {
+              curArg = conversions["USVString"](curArg, {
+                context: "Failed to execute 'set' on 'FormData': parameter 3"
+              });
+            }
+            args.push(curArg);
+          }
+      }
+      return esValue[implSymbol].set(...args);
+    }
+
+    keys() {
+      if (!exports.is(this)) {
+        throw new TypeError("'keys' called on an object that is not a valid instance of FormData.");
+      }
+      return exports.createDefaultIterator(this, "key");
+    }
+
+    values() {
+      if (!exports.is(this)) {
+        throw new TypeError("'values' called on an object that is not a valid instance of FormData.");
+      }
+      return exports.createDefaultIterator(this, "value");
+    }
+
+    entries() {
+      if (!exports.is(this)) {
+        throw new TypeError("'entries' called on an object that is not a valid instance of FormData.");
+      }
+      return exports.createDefaultIterator(this, "key+value");
+    }
+
+    forEach(callback) {
+      if (!exports.is(this)) {
+        throw new TypeError("'forEach' called on an object that is not a valid instance of FormData.");
+      }
+      if (arguments.length < 1) {
+        throw new TypeError("Failed to execute 'forEach' on 'iterable': 1 argument required, " + "but only 0 present.");
+      }
+      callback = Function.convert(callback, {
+        context: "Failed to execute 'forEach' on 'iterable': The callback provided as parameter 1"
+      });
+      const thisArg = arguments[1];
+      let pairs = Array.from(this[implSymbol]);
+      let i = 0;
+      while (i < pairs.length) {
+        const [key, value] = pairs[i].map(utils.tryWrapperForImpl);
+        callback.call(thisArg, value, key, this);
+        pairs = Array.from(this[implSymbol]);
+        i++;
+      }
+    }
+  }
+  Object.defineProperties(FormData.prototype, {
+    append: { enumerable: true },
+    delete: { enumerable: true },
+    get: { enumerable: true },
+    getAll: { enumerable: true },
+    has: { enumerable: true },
+    set: { enumerable: true },
+    keys: { enumerable: true },
+    values: { enumerable: true },
+    entries: { enumerable: true },
+    forEach: { enumerable: true },
+    [Symbol.toStringTag]: { value: "FormData", configurable: true },
+    [Symbol.iterator]: { value: FormData.prototype.entries, configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = FormData;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: FormData
+  });
+};
+
+const Impl = require("../xhr/FormData-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Function.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Function.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Function.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (typeof value !== "function") {
+    throw new TypeError(context + " is not a function");
+  }
+
+  function invokeTheCallbackFunction(...args) {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    for (let i = 0; i < args.length; i++) {
+      args[i] = utils.tryWrapperForImpl(args[i]);
+    }
+
+    callResult = Reflect.apply(value, thisArg, args);
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  }
+
+  invokeTheCallbackFunction.construct = (...args) => {
+    for (let i = 0; i < args.length; i++) {
+      args[i] = utils.tryWrapperForImpl(args[i]);
+    }
+
+    let callResult = Reflect.construct(value, args);
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/GetRootNodeOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/GetRootNodeOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/GetRootNodeOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "composed";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'composed' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAnchorElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAnchorElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAnchorElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,915 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLAnchorElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLAnchorElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLAnchorElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLAnchorElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLAnchorElement before HTMLElement");
+  }
+  class HTMLAnchorElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "target");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set target(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set target' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'target' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "target", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get download() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get download' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "download");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set download(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set download' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'download' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "download", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rel' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rel");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rel' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rel' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rel", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get relList() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get relList' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      return utils.getSameObject(this, "relList", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["relList"]);
+      });
+    }
+
+    set relList(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set relList' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      const Q = esValue["relList"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'relList' is not an object");
+      }
+      Reflect.set(Q, "value", V);
+    }
+
+    get hreflang() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hreflang' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "hreflang");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hreflang(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hreflang' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'hreflang' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "hreflang", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get text() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get text' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["text"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set text(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set text' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'text' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["text"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get coords() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get coords' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "coords");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set coords(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set coords' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'coords' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "coords", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get charset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get charset' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charset");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set charset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set charset' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'charset' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charset", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rev() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rev' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rev");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rev(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rev' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rev' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rev", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get shape() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get shape' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "shape");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set shape(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set shape' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'shape' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "shape", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get href() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get href' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["href"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set href(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set href' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'href' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["href"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    toString() {
+      const esValue = this;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toString' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["href"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get origin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get origin' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      return esValue[implSymbol]["origin"];
+    }
+
+    get protocol() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get protocol' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["protocol"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set protocol(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set protocol' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'protocol' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["protocol"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get username() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get username' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["username"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set username(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set username' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'username' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["username"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get password() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get password' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["password"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set password(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set password' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'password' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["password"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get host() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get host' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["host"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set host(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set host' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'host' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["host"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hostname() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hostname' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["hostname"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hostname(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hostname' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'hostname' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["hostname"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get port() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get port' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["port"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set port(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set port' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'port' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["port"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get pathname() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get pathname' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["pathname"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set pathname(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set pathname' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'pathname' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["pathname"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get search() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get search' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["search"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set search(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set search' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'search' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["search"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hash() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hash' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["hash"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hash(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hash' called on an object that is not a valid instance of HTMLAnchorElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'hash' property on 'HTMLAnchorElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["hash"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLAnchorElement.prototype, {
+    target: { enumerable: true },
+    download: { enumerable: true },
+    rel: { enumerable: true },
+    relList: { enumerable: true },
+    hreflang: { enumerable: true },
+    type: { enumerable: true },
+    text: { enumerable: true },
+    coords: { enumerable: true },
+    charset: { enumerable: true },
+    name: { enumerable: true },
+    rev: { enumerable: true },
+    shape: { enumerable: true },
+    href: { enumerable: true },
+    toString: { enumerable: true },
+    origin: { enumerable: true },
+    protocol: { enumerable: true },
+    username: { enumerable: true },
+    password: { enumerable: true },
+    host: { enumerable: true },
+    hostname: { enumerable: true },
+    port: { enumerable: true },
+    pathname: { enumerable: true },
+    search: { enumerable: true },
+    hash: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLAnchorElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLAnchorElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLAnchorElement
+  });
+};
+
+const Impl = require("../nodes/HTMLAnchorElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAreaElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAreaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAreaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,739 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLAreaElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLAreaElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLAreaElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLAreaElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLAreaElement before HTMLElement");
+  }
+  class HTMLAreaElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get alt() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get alt' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "alt");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set alt(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set alt' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'alt' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "alt", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get coords() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get coords' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "coords");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set coords(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set coords' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'coords' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "coords", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get shape() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get shape' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "shape");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set shape(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set shape' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'shape' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "shape", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "target");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set target(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set target' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'target' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "target", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rel' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rel");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rel' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rel' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rel", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get relList() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get relList' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      return utils.getSameObject(this, "relList", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["relList"]);
+      });
+    }
+
+    set relList(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set relList' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      const Q = esValue["relList"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'relList' is not an object");
+      }
+      Reflect.set(Q, "value", V);
+    }
+
+    get noHref() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get noHref' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "nohref");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set noHref(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set noHref' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'noHref' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "nohref", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "nohref");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get href() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get href' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["href"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set href(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set href' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'href' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["href"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    toString() {
+      const esValue = this;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toString' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["href"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get origin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get origin' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      return esValue[implSymbol]["origin"];
+    }
+
+    get protocol() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get protocol' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["protocol"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set protocol(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set protocol' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'protocol' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["protocol"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get username() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get username' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["username"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set username(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set username' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'username' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["username"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get password() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get password' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["password"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set password(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set password' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'password' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["password"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get host() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get host' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["host"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set host(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set host' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'host' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["host"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hostname() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hostname' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["hostname"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hostname(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hostname' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'hostname' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["hostname"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get port() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get port' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["port"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set port(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set port' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'port' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["port"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get pathname() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get pathname' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["pathname"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set pathname(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set pathname' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'pathname' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["pathname"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get search() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get search' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["search"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set search(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set search' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'search' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["search"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hash() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hash' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["hash"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hash(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hash' called on an object that is not a valid instance of HTMLAreaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'hash' property on 'HTMLAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["hash"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLAreaElement.prototype, {
+    alt: { enumerable: true },
+    coords: { enumerable: true },
+    shape: { enumerable: true },
+    target: { enumerable: true },
+    rel: { enumerable: true },
+    relList: { enumerable: true },
+    noHref: { enumerable: true },
+    href: { enumerable: true },
+    toString: { enumerable: true },
+    origin: { enumerable: true },
+    protocol: { enumerable: true },
+    username: { enumerable: true },
+    password: { enumerable: true },
+    host: { enumerable: true },
+    hostname: { enumerable: true },
+    port: { enumerable: true },
+    pathname: { enumerable: true },
+    search: { enumerable: true },
+    hash: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLAreaElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLAreaElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLAreaElement
+  });
+};
+
+const Impl = require("../nodes/HTMLAreaElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAudioElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAudioElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLAudioElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,115 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLMediaElement = require("./HTMLMediaElement.js");
+
+const interfaceName = "HTMLAudioElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLAudioElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLAudioElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLAudioElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLMediaElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLMediaElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLAudioElement before HTMLMediaElement");
+  }
+  class HTMLAudioElement extends globalObject.HTMLMediaElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+  }
+  Object.defineProperties(HTMLAudioElement.prototype, {
+    [Symbol.toStringTag]: { value: "HTMLAudioElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLAudioElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLAudioElement
+  });
+};
+
+const Impl = require("../nodes/HTMLAudioElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBRElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBRElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBRElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLBRElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLBRElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLBRElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLBRElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLBRElement before HTMLElement");
+  }
+  class HTMLBRElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get clear() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clear' called on an object that is not a valid instance of HTMLBRElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "clear");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set clear(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set clear' called on an object that is not a valid instance of HTMLBRElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'clear' property on 'HTMLBRElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "clear", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLBRElement.prototype, {
+    clear: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLBRElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLBRElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLBRElement
+  });
+};
+
+const Impl = require("../nodes/HTMLBRElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBaseElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBaseElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBaseElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,188 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLBaseElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLBaseElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLBaseElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLBaseElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLBaseElement before HTMLElement");
+  }
+  class HTMLBaseElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get href() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get href' called on an object that is not a valid instance of HTMLBaseElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["href"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set href(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set href' called on an object that is not a valid instance of HTMLBaseElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'href' property on 'HTMLBaseElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["href"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of HTMLBaseElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "target");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set target(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set target' called on an object that is not a valid instance of HTMLBaseElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'target' property on 'HTMLBaseElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "target", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLBaseElement.prototype, {
+    href: { enumerable: true },
+    target: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLBaseElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLBaseElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLBaseElement
+  });
+};
+
+const Impl = require("../nodes/HTMLBaseElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBodyElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBodyElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLBodyElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,808 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const OnBeforeUnloadEventHandlerNonNull = require("./OnBeforeUnloadEventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLBodyElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLBodyElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLBodyElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLBodyElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLBodyElement before HTMLElement");
+  }
+  class HTMLBodyElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get text() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get text' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "text");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set text(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set text' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'text' property on 'HTMLBodyElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "text", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get link() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get link' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "link");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set link(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set link' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'link' property on 'HTMLBodyElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "link", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vLink() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vLink' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "vlink");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vLink(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vLink' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'vLink' property on 'HTMLBodyElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "vlink", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get aLink() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get aLink' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "alink");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set aLink(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set aLink' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'aLink' property on 'HTMLBodyElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "alink", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get bgColor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bgColor' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "bgcolor");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set bgColor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set bgColor' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'bgColor' property on 'HTMLBodyElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "bgcolor", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get background() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get background' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "background");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set background(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set background' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'background' property on 'HTMLBodyElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "background", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get onafterprint() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onafterprint' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onafterprint"]);
+    }
+
+    set onafterprint(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onafterprint' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onafterprint' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onafterprint"] = V;
+    }
+
+    get onbeforeprint() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onbeforeprint' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onbeforeprint"]);
+    }
+
+    set onbeforeprint(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onbeforeprint' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeprint' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onbeforeprint"] = V;
+    }
+
+    get onbeforeunload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onbeforeunload' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onbeforeunload"]);
+    }
+
+    set onbeforeunload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onbeforeunload' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnBeforeUnloadEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeunload' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onbeforeunload"] = V;
+    }
+
+    get onhashchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onhashchange' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onhashchange"]);
+    }
+
+    set onhashchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onhashchange' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onhashchange' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onhashchange"] = V;
+    }
+
+    get onlanguagechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onlanguagechange' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onlanguagechange"]);
+    }
+
+    set onlanguagechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onlanguagechange' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onlanguagechange' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onlanguagechange"] = V;
+    }
+
+    get onmessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmessage' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessage"]);
+    }
+
+    set onmessage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmessage' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessage' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessage"] = V;
+    }
+
+    get onmessageerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onmessageerror' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessageerror"]);
+    }
+
+    set onmessageerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onmessageerror' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessageerror' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessageerror"] = V;
+    }
+
+    get onoffline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onoffline' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onoffline"]);
+    }
+
+    set onoffline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onoffline' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onoffline' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onoffline"] = V;
+    }
+
+    get ononline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ononline' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ononline"]);
+    }
+
+    set ononline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ononline' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ononline' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ononline"] = V;
+    }
+
+    get onpagehide() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpagehide' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpagehide"]);
+    }
+
+    set onpagehide(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpagehide' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpagehide' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpagehide"] = V;
+    }
+
+    get onpageshow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpageshow' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpageshow"]);
+    }
+
+    set onpageshow(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpageshow' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpageshow' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpageshow"] = V;
+    }
+
+    get onpopstate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpopstate' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpopstate"]);
+    }
+
+    set onpopstate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpopstate' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpopstate' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpopstate"] = V;
+    }
+
+    get onrejectionhandled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onrejectionhandled' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onrejectionhandled"]);
+    }
+
+    set onrejectionhandled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onrejectionhandled' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onrejectionhandled' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onrejectionhandled"] = V;
+    }
+
+    get onstorage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onstorage' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onstorage"]);
+    }
+
+    set onstorage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onstorage' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onstorage' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onstorage"] = V;
+    }
+
+    get onunhandledrejection() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onunhandledrejection' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onunhandledrejection"]);
+    }
+
+    set onunhandledrejection(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onunhandledrejection' called on an object that is not a valid instance of HTMLBodyElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onunhandledrejection' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onunhandledrejection"] = V;
+    }
+
+    get onunload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onunload' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onunload"]);
+    }
+
+    set onunload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onunload' called on an object that is not a valid instance of HTMLBodyElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onunload' property on 'HTMLBodyElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onunload"] = V;
+    }
+  }
+  Object.defineProperties(HTMLBodyElement.prototype, {
+    text: { enumerable: true },
+    link: { enumerable: true },
+    vLink: { enumerable: true },
+    aLink: { enumerable: true },
+    bgColor: { enumerable: true },
+    background: { enumerable: true },
+    onafterprint: { enumerable: true },
+    onbeforeprint: { enumerable: true },
+    onbeforeunload: { enumerable: true },
+    onhashchange: { enumerable: true },
+    onlanguagechange: { enumerable: true },
+    onmessage: { enumerable: true },
+    onmessageerror: { enumerable: true },
+    onoffline: { enumerable: true },
+    ononline: { enumerable: true },
+    onpagehide: { enumerable: true },
+    onpageshow: { enumerable: true },
+    onpopstate: { enumerable: true },
+    onrejectionhandled: { enumerable: true },
+    onstorage: { enumerable: true },
+    onunhandledrejection: { enumerable: true },
+    onunload: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLBodyElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLBodyElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLBodyElement
+  });
+};
+
+const Impl = require("../nodes/HTMLBodyElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLButtonElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLButtonElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLButtonElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,487 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLButtonElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLButtonElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLButtonElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLButtonElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLButtonElement before HTMLElement");
+  }
+  class HTMLButtonElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reportValidity' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLButtonElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLButtonElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLButtonElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    get autofocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get autofocus' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "autofocus");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autofocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set autofocus' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'autofocus' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "autofocus", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "autofocus");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get formNoValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get formNoValidate' called on an object that is not a valid instance of HTMLButtonElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "formnovalidate");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set formNoValidate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set formNoValidate' called on an object that is not a valid instance of HTMLButtonElement."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'formNoValidate' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "formnovalidate", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "formnovalidate");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get formTarget() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get formTarget' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "formtarget");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set formTarget(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set formTarget' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'formTarget' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "formtarget", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["type"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["type"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "value");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLButtonElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "value", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get willValidate' called on an object that is not a valid instance of HTMLButtonElement."
+        );
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLButtonElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLButtonElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+  }
+  Object.defineProperties(HTMLButtonElement.prototype, {
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    autofocus: { enumerable: true },
+    disabled: { enumerable: true },
+    form: { enumerable: true },
+    formNoValidate: { enumerable: true },
+    formTarget: { enumerable: true },
+    name: { enumerable: true },
+    type: { enumerable: true },
+    value: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    labels: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLButtonElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLButtonElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLButtonElement
+  });
+};
+
+const Impl = require("../nodes/HTMLButtonElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLCanvasElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLCanvasElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLCanvasElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,291 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const BlobCallback = require("./BlobCallback.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLCanvasElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLCanvasElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLCanvasElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLCanvasElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLCanvasElement before HTMLElement");
+  }
+  class HTMLCanvasElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    getContext(contextId) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getContext' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getContext' on 'HTMLCanvasElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getContext' on 'HTMLCanvasElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      for (let i = 1; i < arguments.length; i++) {
+        let curArg = arguments[i];
+        curArg = conversions["any"](curArg, {
+          context: "Failed to execute 'getContext' on 'HTMLCanvasElement': parameter " + (i + 1)
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getContext(...args));
+    }
+
+    toDataURL() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toDataURL' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'toDataURL' on 'HTMLCanvasElement': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["any"](curArg, {
+            context: "Failed to execute 'toDataURL' on 'HTMLCanvasElement': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].toDataURL(...args);
+    }
+
+    toBlob(callback) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toBlob' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'toBlob' on 'HTMLCanvasElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = BlobCallback.convert(curArg, {
+          context: "Failed to execute 'toBlob' on 'HTMLCanvasElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'toBlob' on 'HTMLCanvasElement': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["any"](curArg, {
+            context: "Failed to execute 'toBlob' on 'HTMLCanvasElement': parameter 3"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].toBlob(...args);
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["width"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'width' property on 'HTMLCanvasElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["width"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["height"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLCanvasElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'height' property on 'HTMLCanvasElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["height"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLCanvasElement.prototype, {
+    getContext: { enumerable: true },
+    toDataURL: { enumerable: true },
+    toBlob: { enumerable: true },
+    width: { enumerable: true },
+    height: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLCanvasElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLCanvasElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLCanvasElement
+  });
+};
+
+const Impl = require("../nodes/HTMLCanvasElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLCollection.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLCollection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLCollection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,358 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "HTMLCollection";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLCollection'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLCollection"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLCollection is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class HTMLCollection {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of HTMLCollection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'HTMLCollection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'HTMLCollection': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    namedItem(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'namedItem' called on an object that is not a valid instance of HTMLCollection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'namedItem' on 'HTMLCollection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'namedItem' on 'HTMLCollection': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].namedItem(...args));
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of HTMLCollection.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(HTMLCollection.prototype, {
+    item: { enumerable: true },
+    namedItem: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLCollection", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLCollection;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLCollection
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of target[implSymbol][utils.supportedPropertyNames]) {
+      if (!(key in target)) {
+        keys.add(`${key}`);
+      }
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    const namedValue = target[implSymbol].namedItem(P);
+
+    if (namedValue !== null && !(P in target) && !ignoreNamedProps) {
+      return {
+        writable: false,
+        enumerable: false,
+        configurable: true,
+        value: utils.tryWrapperForImpl(namedValue)
+      };
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+    if (!utils.hasOwn(target, P)) {
+      const creating = !(target[implSymbol].namedItem(P) !== null);
+      if (!creating) {
+        return false;
+      }
+    }
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    if (target[implSymbol].namedItem(P) !== null && !(P in target)) {
+      return false;
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../nodes/HTMLCollection-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDListElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDListElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDListElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDListElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDListElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDListElement before HTMLElement");
+  }
+  class HTMLDListElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get compact() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get compact' called on an object that is not a valid instance of HTMLDListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "compact");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set compact(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set compact' called on an object that is not a valid instance of HTMLDListElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'compact' property on 'HTMLDListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "compact", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "compact");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLDListElement.prototype, {
+    compact: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDListElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDListElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDListElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDListElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDataElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDataElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDataElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDataElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDataElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDataElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDataElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDataElement before HTMLElement");
+  }
+  class HTMLDataElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLDataElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "value");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLDataElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLDataElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "value", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLDataElement.prototype, {
+    value: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDataElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDataElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDataElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDataElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDataListElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDataListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDataListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,128 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDataListElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDataListElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDataListElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDataListElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDataListElement before HTMLElement");
+  }
+  class HTMLDataListElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get options() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get options' called on an object that is not a valid instance of HTMLDataListElement.");
+      }
+
+      return utils.getSameObject(this, "options", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["options"]);
+      });
+    }
+  }
+  Object.defineProperties(HTMLDataListElement.prototype, {
+    options: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDataListElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDataListElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDataListElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDataListElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDetailsElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDetailsElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDetailsElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDetailsElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDetailsElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDetailsElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDetailsElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDetailsElement before HTMLElement");
+  }
+  class HTMLDetailsElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get open() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get open' called on an object that is not a valid instance of HTMLDetailsElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "open");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set open(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set open' called on an object that is not a valid instance of HTMLDetailsElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'open' property on 'HTMLDetailsElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "open", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "open");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLDetailsElement.prototype, {
+    open: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDetailsElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDetailsElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDetailsElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDetailsElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDialogElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDialogElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDialogElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDialogElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDialogElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDialogElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDialogElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDialogElement before HTMLElement");
+  }
+  class HTMLDialogElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get open() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get open' called on an object that is not a valid instance of HTMLDialogElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "open");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set open(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set open' called on an object that is not a valid instance of HTMLDialogElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'open' property on 'HTMLDialogElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "open", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "open");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLDialogElement.prototype, {
+    open: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDialogElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDialogElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDialogElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDialogElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDirectoryElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDirectoryElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDirectoryElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDirectoryElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDirectoryElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDirectoryElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDirectoryElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDirectoryElement before HTMLElement");
+  }
+  class HTMLDirectoryElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get compact() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get compact' called on an object that is not a valid instance of HTMLDirectoryElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "compact");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set compact(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set compact' called on an object that is not a valid instance of HTMLDirectoryElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'compact' property on 'HTMLDirectoryElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "compact", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "compact");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLDirectoryElement.prototype, {
+    compact: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDirectoryElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDirectoryElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDirectoryElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDirectoryElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDivElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDivElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLDivElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLDivElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLDivElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLDivElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLDivElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLDivElement before HTMLElement");
+  }
+  class HTMLDivElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLDivElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLDivElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLDivElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLDivElement.prototype, {
+    align: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLDivElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLDivElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLDivElement
+  });
+};
+
+const Impl = require("../nodes/HTMLDivElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,2269 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const OnErrorEventHandlerNonNull = require("./OnErrorEventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Element = require("./Element.js");
+
+const interfaceName = "HTMLElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Element._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Element === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLElement before Element");
+  }
+  class HTMLElement extends globalObject.Element {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    click() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'click' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol].click();
+    }
+
+    focus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'focus' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol].focus();
+    }
+
+    blur() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'blur' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol].blur();
+    }
+
+    get title() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get title' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "title");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set title(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set title' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'title' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "title", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get lang() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lang' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "lang");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set lang(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set lang' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'lang' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "lang", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get translate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get translate' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["translate"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set translate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set translate' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'translate' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["translate"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get dir() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dir' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["dir"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set dir(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set dir' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'dir' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["dir"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hidden() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hidden' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "hidden");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hidden(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hidden' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'hidden' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "hidden", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "hidden");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get accessKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get accessKey' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "accesskey");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set accessKey(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set accessKey' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'accessKey' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "accesskey", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get draggable() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get draggable' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["draggable"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set draggable(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set draggable' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'draggable' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["draggable"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get offsetParent() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get offsetParent' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["offsetParent"]);
+    }
+
+    get offsetTop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get offsetTop' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol]["offsetTop"];
+    }
+
+    get offsetLeft() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get offsetLeft' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol]["offsetLeft"];
+    }
+
+    get offsetWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get offsetWidth' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol]["offsetWidth"];
+    }
+
+    get offsetHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get offsetHeight' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return esValue[implSymbol]["offsetHeight"];
+    }
+
+    get style() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get style' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.getSameObject(this, "style", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["style"]);
+      });
+    }
+
+    set style(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set style' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      const Q = esValue["style"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'style' is not an object");
+      }
+      Reflect.set(Q, "cssText", V);
+    }
+
+    get onabort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onabort' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onabort"]);
+    }
+
+    set onabort(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onabort' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onabort' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onabort"] = V;
+    }
+
+    get onauxclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onauxclick' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onauxclick"]);
+    }
+
+    set onauxclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onauxclick' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onauxclick' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onauxclick"] = V;
+    }
+
+    get onblur() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onblur' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onblur"]);
+    }
+
+    set onblur(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onblur' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onblur' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onblur"] = V;
+    }
+
+    get oncancel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncancel' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncancel"]);
+    }
+
+    set oncancel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncancel' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncancel' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncancel"] = V;
+    }
+
+    get oncanplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncanplay' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncanplay"]);
+    }
+
+    set oncanplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncanplay' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncanplay' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncanplay"] = V;
+    }
+
+    get oncanplaythrough() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncanplaythrough' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncanplaythrough"]);
+    }
+
+    set oncanplaythrough(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncanplaythrough' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncanplaythrough' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncanplaythrough"] = V;
+    }
+
+    get onchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onchange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onchange"]);
+    }
+
+    set onchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onchange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onchange' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onchange"] = V;
+    }
+
+    get onclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclick' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclick"]);
+    }
+
+    set onclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclick' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclick' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclick"] = V;
+    }
+
+    get onclose() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclose' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclose"]);
+    }
+
+    set onclose(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclose' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclose' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclose"] = V;
+    }
+
+    get oncontextmenu() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncontextmenu' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncontextmenu"]);
+    }
+
+    set oncontextmenu(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncontextmenu' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncontextmenu' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncontextmenu"] = V;
+    }
+
+    get oncuechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncuechange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncuechange"]);
+    }
+
+    set oncuechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncuechange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncuechange' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncuechange"] = V;
+    }
+
+    get ondblclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondblclick' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondblclick"]);
+    }
+
+    set ondblclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondblclick' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondblclick' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondblclick"] = V;
+    }
+
+    get ondrag() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondrag' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondrag"]);
+    }
+
+    set ondrag(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondrag' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondrag' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondrag"] = V;
+    }
+
+    get ondragend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragend' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragend"]);
+    }
+
+    set ondragend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragend' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragend' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragend"] = V;
+    }
+
+    get ondragenter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragenter' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragenter"]);
+    }
+
+    set ondragenter(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragenter' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragenter' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragenter"] = V;
+    }
+
+    get ondragleave() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragleave' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragleave"]);
+    }
+
+    set ondragleave(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragleave' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragleave' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragleave"] = V;
+    }
+
+    get ondragover() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragover' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragover"]);
+    }
+
+    set ondragover(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragover' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragover' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragover"] = V;
+    }
+
+    get ondragstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragstart' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragstart"]);
+    }
+
+    set ondragstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragstart' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragstart' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragstart"] = V;
+    }
+
+    get ondrop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondrop' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondrop"]);
+    }
+
+    set ondrop(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondrop' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondrop' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondrop"] = V;
+    }
+
+    get ondurationchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondurationchange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondurationchange"]);
+    }
+
+    set ondurationchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondurationchange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondurationchange' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondurationchange"] = V;
+    }
+
+    get onemptied() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onemptied' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onemptied"]);
+    }
+
+    set onemptied(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onemptied' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onemptied' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onemptied"] = V;
+    }
+
+    get onended() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onended' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onended"]);
+    }
+
+    set onended(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onended' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onended' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onended"] = V;
+    }
+
+    get onerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onerror' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onerror"]);
+    }
+
+    set onerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onerror' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnErrorEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onerror"] = V;
+    }
+
+    get onfocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onfocus' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onfocus"]);
+    }
+
+    set onfocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onfocus' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onfocus' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onfocus"] = V;
+    }
+
+    get oninput() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oninput' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oninput"]);
+    }
+
+    set oninput(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oninput' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oninput' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oninput"] = V;
+    }
+
+    get oninvalid() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oninvalid' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oninvalid"]);
+    }
+
+    set oninvalid(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oninvalid' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oninvalid' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oninvalid"] = V;
+    }
+
+    get onkeydown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeydown' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeydown"]);
+    }
+
+    set onkeydown(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeydown' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeydown' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeydown"] = V;
+    }
+
+    get onkeypress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeypress' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeypress"]);
+    }
+
+    set onkeypress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeypress' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeypress' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeypress"] = V;
+    }
+
+    get onkeyup() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeyup' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeyup"]);
+    }
+
+    set onkeyup(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeyup' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeyup' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeyup"] = V;
+    }
+
+    get onload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onload' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onload"]);
+    }
+
+    set onload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onload' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onload' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onload"] = V;
+    }
+
+    get onloadeddata() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadeddata' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadeddata"]);
+    }
+
+    set onloadeddata(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadeddata' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadeddata' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadeddata"] = V;
+    }
+
+    get onloadedmetadata() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadedmetadata' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadedmetadata"]);
+    }
+
+    set onloadedmetadata(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadedmetadata' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadedmetadata' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadedmetadata"] = V;
+    }
+
+    get onloadend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadend' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadend"]);
+    }
+
+    set onloadend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadend' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadend' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadend"] = V;
+    }
+
+    get onloadstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadstart' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadstart"]);
+    }
+
+    set onloadstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadstart' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadstart' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadstart"] = V;
+    }
+
+    get onmousedown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmousedown' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmousedown"]);
+    }
+
+    set onmousedown(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmousedown' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmousedown' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmousedown"] = V;
+    }
+
+    get onmouseenter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseenter"]);
+    }
+
+    set onmouseenter(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseenter' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseenter"] = V;
+    }
+
+    get onmouseleave() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseleave"]);
+    }
+
+    set onmouseleave(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseleave' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseleave"] = V;
+    }
+
+    get onmousemove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmousemove' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmousemove"]);
+    }
+
+    set onmousemove(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmousemove' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmousemove' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmousemove"] = V;
+    }
+
+    get onmouseout() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseout' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseout"]);
+    }
+
+    set onmouseout(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseout' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseout' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseout"] = V;
+    }
+
+    get onmouseover() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseover' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseover"]);
+    }
+
+    set onmouseover(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseover' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseover' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseover"] = V;
+    }
+
+    get onmouseup() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseup' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseup"]);
+    }
+
+    set onmouseup(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseup' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseup' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseup"] = V;
+    }
+
+    get onwheel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onwheel' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onwheel"]);
+    }
+
+    set onwheel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onwheel' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onwheel' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onwheel"] = V;
+    }
+
+    get onpause() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpause' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpause"]);
+    }
+
+    set onpause(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpause' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpause' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpause"] = V;
+    }
+
+    get onplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onplay' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onplay"]);
+    }
+
+    set onplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onplay' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onplay' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onplay"] = V;
+    }
+
+    get onplaying() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onplaying' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onplaying"]);
+    }
+
+    set onplaying(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onplaying' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onplaying' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onplaying"] = V;
+    }
+
+    get onprogress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onprogress' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onprogress"]);
+    }
+
+    set onprogress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onprogress' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onprogress' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onprogress"] = V;
+    }
+
+    get onratechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onratechange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onratechange"]);
+    }
+
+    set onratechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onratechange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onratechange' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onratechange"] = V;
+    }
+
+    get onreset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onreset' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onreset"]);
+    }
+
+    set onreset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onreset' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onreset' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onreset"] = V;
+    }
+
+    get onresize() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onresize' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onresize"]);
+    }
+
+    set onresize(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onresize' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onresize' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onresize"] = V;
+    }
+
+    get onscroll() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onscroll' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onscroll"]);
+    }
+
+    set onscroll(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onscroll' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onscroll' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onscroll"] = V;
+    }
+
+    get onsecuritypolicyviolation() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onsecuritypolicyviolation' called on an object that is not a valid instance of HTMLElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsecuritypolicyviolation"]);
+    }
+
+    set onsecuritypolicyviolation(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onsecuritypolicyviolation' called on an object that is not a valid instance of HTMLElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsecuritypolicyviolation' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsecuritypolicyviolation"] = V;
+    }
+
+    get onseeked() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onseeked' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onseeked"]);
+    }
+
+    set onseeked(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onseeked' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onseeked' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onseeked"] = V;
+    }
+
+    get onseeking() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onseeking' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onseeking"]);
+    }
+
+    set onseeking(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onseeking' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onseeking' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onseeking"] = V;
+    }
+
+    get onselect() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onselect' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onselect"]);
+    }
+
+    set onselect(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onselect' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onselect' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onselect"] = V;
+    }
+
+    get onstalled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onstalled' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onstalled"]);
+    }
+
+    set onstalled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onstalled' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onstalled' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onstalled"] = V;
+    }
+
+    get onsubmit() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onsubmit' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsubmit"]);
+    }
+
+    set onsubmit(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onsubmit' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsubmit' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsubmit"] = V;
+    }
+
+    get onsuspend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onsuspend' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsuspend"]);
+    }
+
+    set onsuspend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onsuspend' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsuspend' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsuspend"] = V;
+    }
+
+    get ontimeupdate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ontimeupdate' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontimeupdate"]);
+    }
+
+    set ontimeupdate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ontimeupdate' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontimeupdate' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontimeupdate"] = V;
+    }
+
+    get ontoggle() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ontoggle' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontoggle"]);
+    }
+
+    set ontoggle(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ontoggle' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontoggle' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontoggle"] = V;
+    }
+
+    get onvolumechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onvolumechange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onvolumechange"]);
+    }
+
+    set onvolumechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onvolumechange' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onvolumechange' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onvolumechange"] = V;
+    }
+
+    get onwaiting() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onwaiting' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onwaiting"]);
+    }
+
+    set onwaiting(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onwaiting' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onwaiting' property on 'HTMLElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onwaiting"] = V;
+    }
+
+    get dataset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dataset' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      return utils.getSameObject(this, "dataset", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["dataset"]);
+      });
+    }
+
+    get nonce() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nonce' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      const value = esValue[implSymbol].getAttributeNS(null, "nonce");
+      return value === null ? "" : value;
+    }
+
+    set nonce(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set nonce' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'nonce' property on 'HTMLElement': The provided value"
+      });
+
+      esValue[implSymbol].setAttributeNS(null, "nonce", V);
+    }
+
+    get tabIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tabIndex' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["tabIndex"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set tabIndex(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set tabIndex' called on an object that is not a valid instance of HTMLElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'tabIndex' property on 'HTMLElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["tabIndex"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLElement.prototype, {
+    click: { enumerable: true },
+    focus: { enumerable: true },
+    blur: { enumerable: true },
+    title: { enumerable: true },
+    lang: { enumerable: true },
+    translate: { enumerable: true },
+    dir: { enumerable: true },
+    hidden: { enumerable: true },
+    accessKey: { enumerable: true },
+    draggable: { enumerable: true },
+    offsetParent: { enumerable: true },
+    offsetTop: { enumerable: true },
+    offsetLeft: { enumerable: true },
+    offsetWidth: { enumerable: true },
+    offsetHeight: { enumerable: true },
+    style: { enumerable: true },
+    onabort: { enumerable: true },
+    onauxclick: { enumerable: true },
+    onblur: { enumerable: true },
+    oncancel: { enumerable: true },
+    oncanplay: { enumerable: true },
+    oncanplaythrough: { enumerable: true },
+    onchange: { enumerable: true },
+    onclick: { enumerable: true },
+    onclose: { enumerable: true },
+    oncontextmenu: { enumerable: true },
+    oncuechange: { enumerable: true },
+    ondblclick: { enumerable: true },
+    ondrag: { enumerable: true },
+    ondragend: { enumerable: true },
+    ondragenter: { enumerable: true },
+    ondragleave: { enumerable: true },
+    ondragover: { enumerable: true },
+    ondragstart: { enumerable: true },
+    ondrop: { enumerable: true },
+    ondurationchange: { enumerable: true },
+    onemptied: { enumerable: true },
+    onended: { enumerable: true },
+    onerror: { enumerable: true },
+    onfocus: { enumerable: true },
+    oninput: { enumerable: true },
+    oninvalid: { enumerable: true },
+    onkeydown: { enumerable: true },
+    onkeypress: { enumerable: true },
+    onkeyup: { enumerable: true },
+    onload: { enumerable: true },
+    onloadeddata: { enumerable: true },
+    onloadedmetadata: { enumerable: true },
+    onloadend: { enumerable: true },
+    onloadstart: { enumerable: true },
+    onmousedown: { enumerable: true },
+    onmouseenter: { enumerable: true },
+    onmouseleave: { enumerable: true },
+    onmousemove: { enumerable: true },
+    onmouseout: { enumerable: true },
+    onmouseover: { enumerable: true },
+    onmouseup: { enumerable: true },
+    onwheel: { enumerable: true },
+    onpause: { enumerable: true },
+    onplay: { enumerable: true },
+    onplaying: { enumerable: true },
+    onprogress: { enumerable: true },
+    onratechange: { enumerable: true },
+    onreset: { enumerable: true },
+    onresize: { enumerable: true },
+    onscroll: { enumerable: true },
+    onsecuritypolicyviolation: { enumerable: true },
+    onseeked: { enumerable: true },
+    onseeking: { enumerable: true },
+    onselect: { enumerable: true },
+    onstalled: { enumerable: true },
+    onsubmit: { enumerable: true },
+    onsuspend: { enumerable: true },
+    ontimeupdate: { enumerable: true },
+    ontoggle: { enumerable: true },
+    onvolumechange: { enumerable: true },
+    onwaiting: { enumerable: true },
+    dataset: { enumerable: true },
+    nonce: { enumerable: true },
+    tabIndex: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLElement
+  });
+};
+
+const Impl = require("../nodes/HTMLElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLEmbedElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLEmbedElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLEmbedElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,346 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLEmbedElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLEmbedElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLEmbedElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLEmbedElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLEmbedElement before HTMLElement");
+  }
+  class HTMLEmbedElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLEmbedElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLEmbedElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLEmbedElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "height");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'height' property on 'HTMLEmbedElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "height", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLEmbedElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLEmbedElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLEmbedElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLEmbedElement.prototype, {
+    src: { enumerable: true },
+    type: { enumerable: true },
+    width: { enumerable: true },
+    height: { enumerable: true },
+    align: { enumerable: true },
+    name: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLEmbedElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLEmbedElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLEmbedElement
+  });
+};
+
+const Impl = require("../nodes/HTMLEmbedElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFieldSetElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFieldSetElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFieldSetElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,315 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLFieldSetElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLFieldSetElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLFieldSetElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLFieldSetElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLFieldSetElement before HTMLElement");
+  }
+  class HTMLFieldSetElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'reportValidity' called on an object that is not a valid instance of HTMLFieldSetElement."
+        );
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLFieldSetElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLFieldSetElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLFieldSetElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLFieldSetElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLFieldSetElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+
+    get elements() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get elements' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      return utils.getSameObject(this, "elements", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["elements"]);
+      });
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get willValidate' called on an object that is not a valid instance of HTMLFieldSetElement."
+        );
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLFieldSetElement.");
+      }
+
+      return utils.getSameObject(this, "validity", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+      });
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLFieldSetElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+  }
+  Object.defineProperties(HTMLFieldSetElement.prototype, {
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    disabled: { enumerable: true },
+    form: { enumerable: true },
+    name: { enumerable: true },
+    type: { enumerable: true },
+    elements: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLFieldSetElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLFieldSetElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLFieldSetElement
+  });
+};
+
+const Impl = require("../nodes/HTMLFieldSetElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFontElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFontElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFontElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,226 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLFontElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLFontElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLFontElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLFontElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLFontElement before HTMLElement");
+  }
+  class HTMLFontElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get color() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get color' called on an object that is not a valid instance of HTMLFontElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "color");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set color(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set color' called on an object that is not a valid instance of HTMLFontElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'color' property on 'HTMLFontElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "color", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get face() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get face' called on an object that is not a valid instance of HTMLFontElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "face");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set face(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set face' called on an object that is not a valid instance of HTMLFontElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'face' property on 'HTMLFontElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "face", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get size() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get size' called on an object that is not a valid instance of HTMLFontElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "size");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set size(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set size' called on an object that is not a valid instance of HTMLFontElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'size' property on 'HTMLFontElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "size", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLFontElement.prototype, {
+    color: { enumerable: true },
+    face: { enumerable: true },
+    size: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLFontElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLFontElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLFontElement
+  });
+};
+
+const Impl = require("../nodes/HTMLFontElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFormElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFormElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFormElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,457 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const HTMLElement = require("./HTMLElement.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "HTMLFormElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLFormElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLFormElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLFormElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLFormElement before HTMLElement");
+  }
+  class HTMLFormElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    submit() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'submit' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      return esValue[implSymbol].submit();
+    }
+
+    requestSubmit() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'requestSubmit' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = HTMLElement.convert(curArg, {
+            context: "Failed to execute 'requestSubmit' on 'HTMLFormElement': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].requestSubmit(...args);
+    }
+
+    reset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reset' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].reset();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reportValidity' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    get acceptCharset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get acceptCharset' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "accept-charset");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set acceptCharset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set acceptCharset' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'acceptCharset' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "accept-charset", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get action() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get action' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["action"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set action(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set action' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'action' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["action"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get enctype() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get enctype' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["enctype"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set enctype(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set enctype' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'enctype' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["enctype"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get method() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get method' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["method"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set method(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set method' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'method' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["method"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get noValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get noValidate' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "novalidate");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set noValidate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set noValidate' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'noValidate' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "novalidate", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "novalidate");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "target");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set target(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set target' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'target' property on 'HTMLFormElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "target", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get elements() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get elements' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      return utils.getSameObject(this, "elements", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["elements"]);
+      });
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of HTMLFormElement.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(HTMLFormElement.prototype, {
+    submit: { enumerable: true },
+    requestSubmit: { enumerable: true },
+    reset: { enumerable: true },
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    acceptCharset: { enumerable: true },
+    action: { enumerable: true },
+    enctype: { enumerable: true },
+    method: { enumerable: true },
+    name: { enumerable: true },
+    noValidate: { enumerable: true },
+    target: { enumerable: true },
+    elements: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLFormElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLFormElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLFormElement
+  });
+};
+
+const Impl = require("../nodes/HTMLFormElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFrameElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFrameElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFrameElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,459 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLFrameElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLFrameElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLFrameElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLFrameElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLFrameElement before HTMLElement");
+  }
+  class HTMLFrameElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get scrolling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scrolling' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "scrolling");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set scrolling(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set scrolling' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'scrolling' property on 'HTMLFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "scrolling", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get frameBorder() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get frameBorder' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "frameborder");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set frameBorder(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set frameBorder' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'frameBorder' property on 'HTMLFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "frameborder", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get longDesc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get longDesc' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "longdesc");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set longDesc(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set longDesc' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'longDesc' property on 'HTMLFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "longdesc", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get noResize() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get noResize' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "noresize");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set noResize(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set noResize' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'noResize' property on 'HTMLFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "noresize", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "noresize");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get contentDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get contentDocument' called on an object that is not a valid instance of HTMLFrameElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["contentDocument"]);
+    }
+
+    get contentWindow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get contentWindow' called on an object that is not a valid instance of HTMLFrameElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["contentWindow"]);
+    }
+
+    get marginHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get marginHeight' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "marginheight");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set marginHeight(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set marginHeight' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'marginHeight' property on 'HTMLFrameElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "marginheight", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get marginWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get marginWidth' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "marginwidth");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set marginWidth(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set marginWidth' called on an object that is not a valid instance of HTMLFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'marginWidth' property on 'HTMLFrameElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "marginwidth", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLFrameElement.prototype, {
+    name: { enumerable: true },
+    scrolling: { enumerable: true },
+    src: { enumerable: true },
+    frameBorder: { enumerable: true },
+    longDesc: { enumerable: true },
+    noResize: { enumerable: true },
+    contentDocument: { enumerable: true },
+    contentWindow: { enumerable: true },
+    marginHeight: { enumerable: true },
+    marginWidth: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLFrameElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLFrameElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLFrameElement
+  });
+};
+
+const Impl = require("../nodes/HTMLFrameElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFrameSetElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFrameSetElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLFrameSetElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,683 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const OnBeforeUnloadEventHandlerNonNull = require("./OnBeforeUnloadEventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLFrameSetElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLFrameSetElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLFrameSetElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLFrameSetElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLFrameSetElement before HTMLElement");
+  }
+  class HTMLFrameSetElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get cols() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cols' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "cols");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set cols(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cols' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'cols' property on 'HTMLFrameSetElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "cols", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rows() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rows' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rows");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rows(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rows' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rows' property on 'HTMLFrameSetElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rows", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get onafterprint() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onafterprint' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onafterprint"]);
+    }
+
+    set onafterprint(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onafterprint' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onafterprint' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onafterprint"] = V;
+    }
+
+    get onbeforeprint() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onbeforeprint' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onbeforeprint"]);
+    }
+
+    set onbeforeprint(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onbeforeprint' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeprint' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onbeforeprint"] = V;
+    }
+
+    get onbeforeunload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onbeforeunload' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onbeforeunload"]);
+    }
+
+    set onbeforeunload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onbeforeunload' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnBeforeUnloadEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeunload' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onbeforeunload"] = V;
+    }
+
+    get onhashchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onhashchange' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onhashchange"]);
+    }
+
+    set onhashchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onhashchange' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onhashchange' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onhashchange"] = V;
+    }
+
+    get onlanguagechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onlanguagechange' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onlanguagechange"]);
+    }
+
+    set onlanguagechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onlanguagechange' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onlanguagechange' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onlanguagechange"] = V;
+    }
+
+    get onmessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmessage' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessage"]);
+    }
+
+    set onmessage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmessage' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessage' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessage"] = V;
+    }
+
+    get onmessageerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onmessageerror' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessageerror"]);
+    }
+
+    set onmessageerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onmessageerror' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessageerror' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessageerror"] = V;
+    }
+
+    get onoffline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onoffline' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onoffline"]);
+    }
+
+    set onoffline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onoffline' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onoffline' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onoffline"] = V;
+    }
+
+    get ononline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ononline' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ononline"]);
+    }
+
+    set ononline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ononline' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ononline' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ononline"] = V;
+    }
+
+    get onpagehide() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onpagehide' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpagehide"]);
+    }
+
+    set onpagehide(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onpagehide' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpagehide' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpagehide"] = V;
+    }
+
+    get onpageshow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onpageshow' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpageshow"]);
+    }
+
+    set onpageshow(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onpageshow' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpageshow' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpageshow"] = V;
+    }
+
+    get onpopstate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onpopstate' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpopstate"]);
+    }
+
+    set onpopstate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onpopstate' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpopstate' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpopstate"] = V;
+    }
+
+    get onrejectionhandled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onrejectionhandled' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onrejectionhandled"]);
+    }
+
+    set onrejectionhandled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onrejectionhandled' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onrejectionhandled' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onrejectionhandled"] = V;
+    }
+
+    get onstorage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onstorage' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onstorage"]);
+    }
+
+    set onstorage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onstorage' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onstorage' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onstorage"] = V;
+    }
+
+    get onunhandledrejection() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onunhandledrejection' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onunhandledrejection"]);
+    }
+
+    set onunhandledrejection(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onunhandledrejection' called on an object that is not a valid instance of HTMLFrameSetElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onunhandledrejection' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onunhandledrejection"] = V;
+    }
+
+    get onunload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onunload' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onunload"]);
+    }
+
+    set onunload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onunload' called on an object that is not a valid instance of HTMLFrameSetElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onunload' property on 'HTMLFrameSetElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onunload"] = V;
+    }
+  }
+  Object.defineProperties(HTMLFrameSetElement.prototype, {
+    cols: { enumerable: true },
+    rows: { enumerable: true },
+    onafterprint: { enumerable: true },
+    onbeforeprint: { enumerable: true },
+    onbeforeunload: { enumerable: true },
+    onhashchange: { enumerable: true },
+    onlanguagechange: { enumerable: true },
+    onmessage: { enumerable: true },
+    onmessageerror: { enumerable: true },
+    onoffline: { enumerable: true },
+    ononline: { enumerable: true },
+    onpagehide: { enumerable: true },
+    onpageshow: { enumerable: true },
+    onpopstate: { enumerable: true },
+    onrejectionhandled: { enumerable: true },
+    onstorage: { enumerable: true },
+    onunhandledrejection: { enumerable: true },
+    onunload: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLFrameSetElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLFrameSetElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLFrameSetElement
+  });
+};
+
+const Impl = require("../nodes/HTMLFrameSetElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHRElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHRElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHRElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,300 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLHRElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLHRElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLHRElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLHRElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLHRElement before HTMLElement");
+  }
+  class HTMLHRElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLHRElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get color() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get color' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "color");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set color(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set color' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'color' property on 'HTMLHRElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "color", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get noShade() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get noShade' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "noshade");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set noShade(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set noShade' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'noShade' property on 'HTMLHRElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "noshade", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "noshade");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get size() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get size' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "size");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set size(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set size' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'size' property on 'HTMLHRElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "size", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLHRElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLHRElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLHRElement.prototype, {
+    align: { enumerable: true },
+    color: { enumerable: true },
+    noShade: { enumerable: true },
+    size: { enumerable: true },
+    width: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLHRElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLHRElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLHRElement
+  });
+};
+
+const Impl = require("../nodes/HTMLHRElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHeadElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHeadElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHeadElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,115 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLHeadElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLHeadElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLHeadElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLHeadElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLHeadElement before HTMLElement");
+  }
+  class HTMLHeadElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+  }
+  Object.defineProperties(HTMLHeadElement.prototype, {
+    [Symbol.toStringTag]: { value: "HTMLHeadElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLHeadElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLHeadElement
+  });
+};
+
+const Impl = require("../nodes/HTMLHeadElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHeadingElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHeadingElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHeadingElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLHeadingElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLHeadingElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLHeadingElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLHeadingElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLHeadingElement before HTMLElement");
+  }
+  class HTMLHeadingElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLHeadingElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLHeadingElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLHeadingElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLHeadingElement.prototype, {
+    align: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLHeadingElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLHeadingElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLHeadingElement
+  });
+};
+
+const Impl = require("../nodes/HTMLHeadingElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHtmlElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHtmlElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLHtmlElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLHtmlElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLHtmlElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLHtmlElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLHtmlElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLHtmlElement before HTMLElement");
+  }
+  class HTMLHtmlElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get version() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get version' called on an object that is not a valid instance of HTMLHtmlElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "version");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set version(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set version' called on an object that is not a valid instance of HTMLHtmlElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'version' property on 'HTMLHtmlElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "version", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLHtmlElement.prototype, {
+    version: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLHtmlElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLHtmlElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLHtmlElement
+  });
+};
+
+const Impl = require("../nodes/HTMLHtmlElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLIFrameElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLIFrameElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLIFrameElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,621 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLIFrameElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLIFrameElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLIFrameElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLIFrameElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLIFrameElement before HTMLElement");
+  }
+  class HTMLIFrameElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    getSVGDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getSVGDocument' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].getSVGDocument());
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get srcdoc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get srcdoc' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "srcdoc");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set srcdoc(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set srcdoc' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'srcdoc' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "srcdoc", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get allowFullscreen() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get allowFullscreen' called on an object that is not a valid instance of HTMLIFrameElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "allowfullscreen");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set allowFullscreen(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set allowFullscreen' called on an object that is not a valid instance of HTMLIFrameElement."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'allowFullscreen' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "allowfullscreen", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "allowfullscreen");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "height");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'height' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "height", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get contentDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get contentDocument' called on an object that is not a valid instance of HTMLIFrameElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["contentDocument"]);
+    }
+
+    get contentWindow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get contentWindow' called on an object that is not a valid instance of HTMLIFrameElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["contentWindow"]);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get scrolling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scrolling' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "scrolling");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set scrolling(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set scrolling' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'scrolling' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "scrolling", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get frameBorder() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get frameBorder' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "frameborder");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set frameBorder(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set frameBorder' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'frameBorder' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "frameborder", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get longDesc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get longDesc' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "longdesc");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set longDesc(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set longDesc' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'longDesc' property on 'HTMLIFrameElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "longdesc", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get marginHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get marginHeight' called on an object that is not a valid instance of HTMLIFrameElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "marginheight");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set marginHeight(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set marginHeight' called on an object that is not a valid instance of HTMLIFrameElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'marginHeight' property on 'HTMLIFrameElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "marginheight", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get marginWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get marginWidth' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "marginwidth");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set marginWidth(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set marginWidth' called on an object that is not a valid instance of HTMLIFrameElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'marginWidth' property on 'HTMLIFrameElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "marginwidth", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLIFrameElement.prototype, {
+    getSVGDocument: { enumerable: true },
+    src: { enumerable: true },
+    srcdoc: { enumerable: true },
+    name: { enumerable: true },
+    allowFullscreen: { enumerable: true },
+    width: { enumerable: true },
+    height: { enumerable: true },
+    contentDocument: { enumerable: true },
+    contentWindow: { enumerable: true },
+    align: { enumerable: true },
+    scrolling: { enumerable: true },
+    frameBorder: { enumerable: true },
+    longDesc: { enumerable: true },
+    marginHeight: { enumerable: true },
+    marginWidth: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLIFrameElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLIFrameElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLIFrameElement
+  });
+};
+
+const Impl = require("../nodes/HTMLIFrameElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLImageElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLImageElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLImageElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,789 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const parseNonNegativeInteger_helpers_strings = require("../helpers/strings.js").parseNonNegativeInteger;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLImageElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLImageElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLImageElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLImageElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLImageElement before HTMLElement");
+  }
+  class HTMLImageElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get alt() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get alt' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "alt");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set alt(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set alt' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'alt' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "alt", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get srcset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get srcset' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "srcset");
+        return value === null ? "" : conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set srcset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set srcset' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'srcset' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "srcset", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get sizes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get sizes' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "sizes");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set sizes(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set sizes' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'sizes' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "sizes", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get crossOrigin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get crossOrigin' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "crossorigin");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set crossOrigin(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set crossOrigin' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'crossOrigin' property on 'HTMLImageElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "crossorigin", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get useMap() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get useMap' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "usemap");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set useMap(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set useMap' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'useMap' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "usemap", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get isMap() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get isMap' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "ismap");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set isMap(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set isMap' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'isMap' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "ismap", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "ismap");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["width"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'width' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["width"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["height"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'height' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["height"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get naturalWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get naturalWidth' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      return esValue[implSymbol]["naturalWidth"];
+    }
+
+    get naturalHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get naturalHeight' called on an object that is not a valid instance of HTMLImageElement."
+        );
+      }
+
+      return esValue[implSymbol]["naturalHeight"];
+    }
+
+    get complete() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get complete' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      return esValue[implSymbol]["complete"];
+    }
+
+    get currentSrc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get currentSrc' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      return esValue[implSymbol]["currentSrc"];
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get lowsrc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lowsrc' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "lowsrc");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set lowsrc(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set lowsrc' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'lowsrc' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "lowsrc", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hspace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hspace' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "hspace");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hspace(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hspace' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'hspace' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "hspace", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vspace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vspace' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "vspace");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vspace(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vspace' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'vspace' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "vspace", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get longDesc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get longDesc' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "longdesc");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set longDesc(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set longDesc' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'longDesc' property on 'HTMLImageElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "longdesc", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get border() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get border' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "border");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set border(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set border' called on an object that is not a valid instance of HTMLImageElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'border' property on 'HTMLImageElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "border", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLImageElement.prototype, {
+    alt: { enumerable: true },
+    src: { enumerable: true },
+    srcset: { enumerable: true },
+    sizes: { enumerable: true },
+    crossOrigin: { enumerable: true },
+    useMap: { enumerable: true },
+    isMap: { enumerable: true },
+    width: { enumerable: true },
+    height: { enumerable: true },
+    naturalWidth: { enumerable: true },
+    naturalHeight: { enumerable: true },
+    complete: { enumerable: true },
+    currentSrc: { enumerable: true },
+    name: { enumerable: true },
+    lowsrc: { enumerable: true },
+    align: { enumerable: true },
+    hspace: { enumerable: true },
+    vspace: { enumerable: true },
+    longDesc: { enumerable: true },
+    border: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLImageElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLImageElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLImageElement
+  });
+};
+
+const Impl = require("../nodes/HTMLImageElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLInputElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLInputElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLInputElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1696 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const SelectionMode = require("./SelectionMode.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const FileList = require("./FileList.js");
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLInputElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLInputElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLInputElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLInputElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLInputElement before HTMLElement");
+  }
+  class HTMLInputElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    stepUp() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'stepUp' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'stepUp' on 'HTMLInputElement': parameter 1"
+          });
+        } else {
+          curArg = 1;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].stepUp(...args);
+    }
+
+    stepDown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'stepDown' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'stepDown' on 'HTMLInputElement': parameter 1"
+          });
+        } else {
+          curArg = 1;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].stepDown(...args);
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reportValidity' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLInputElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLInputElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    select() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'select' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol].select();
+    }
+
+    setRangeText(replacement) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setRangeText' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setRangeText' on 'HTMLInputElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      switch (arguments.length) {
+        case 1:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 1"
+            });
+            args.push(curArg);
+          }
+          break;
+        case 2:
+          throw new TypeError(
+            "Failed to execute 'setRangeText' on 'HTMLInputElement': only " + arguments.length + " arguments present."
+          );
+          break;
+        case 3:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 3"
+            });
+            args.push(curArg);
+          }
+          break;
+        default:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 3"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[3];
+            if (curArg !== undefined) {
+              curArg = SelectionMode.convert(curArg, {
+                context: "Failed to execute 'setRangeText' on 'HTMLInputElement': parameter 4"
+              });
+            } else {
+              curArg = "preserve";
+            }
+            args.push(curArg);
+          }
+      }
+      return esValue[implSymbol].setRangeText(...args);
+    }
+
+    setSelectionRange(start, end) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setSelectionRange' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setSelectionRange' on 'HTMLInputElement': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setSelectionRange' on 'HTMLInputElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setSelectionRange' on 'HTMLInputElement': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'setSelectionRange' on 'HTMLInputElement': parameter 3"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setSelectionRange(...args);
+    }
+
+    get accept() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get accept' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "accept");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set accept(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set accept' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'accept' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "accept", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get alt() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get alt' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "alt");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set alt(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set alt' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'alt' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "alt", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get autocomplete() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get autocomplete' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "autocomplete");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autocomplete(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set autocomplete' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'autocomplete' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "autocomplete", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get autofocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get autofocus' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "autofocus");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autofocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set autofocus' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'autofocus' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "autofocus", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "autofocus");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get defaultChecked() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get defaultChecked' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "checked");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defaultChecked(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set defaultChecked' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'defaultChecked' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "checked", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "checked");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get checked() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get checked' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol]["checked"];
+    }
+
+    set checked(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set checked' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'checked' property on 'HTMLInputElement': The provided value"
+      });
+
+      esValue[implSymbol]["checked"] = V;
+    }
+
+    get dirName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dirName' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "dirname");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set dirName(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set dirName' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'dirName' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "dirname", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get files() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get files' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["files"]);
+    }
+
+    set files(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set files' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = FileList.convert(V, {
+          context: "Failed to set the 'files' property on 'HTMLInputElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["files"] = V;
+    }
+
+    get formNoValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get formNoValidate' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "formnovalidate");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set formNoValidate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set formNoValidate' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'formNoValidate' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "formnovalidate", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "formnovalidate");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get formTarget() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get formTarget' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "formtarget");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set formTarget(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set formTarget' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'formTarget' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "formtarget", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get indeterminate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get indeterminate' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      return esValue[implSymbol]["indeterminate"];
+    }
+
+    set indeterminate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set indeterminate' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'indeterminate' property on 'HTMLInputElement': The provided value"
+      });
+
+      esValue[implSymbol]["indeterminate"] = V;
+    }
+
+    get inputMode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get inputMode' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "inputmode");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set inputMode(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set inputMode' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'inputMode' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "inputmode", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get list() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get list' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["list"]);
+    }
+
+    get max() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get max' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "max");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set max(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set max' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'max' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "max", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get maxLength() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get maxLength' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["maxLength"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set maxLength(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set maxLength' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'maxLength' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["maxLength"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get min() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get min' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "min");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set min(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set min' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'min' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "min", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get minLength() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get minLength' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["minLength"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set minLength(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set minLength' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'minLength' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["minLength"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get multiple() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get multiple' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "multiple");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set multiple(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set multiple' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'multiple' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "multiple", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "multiple");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get pattern() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get pattern' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "pattern");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set pattern(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set pattern' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'pattern' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "pattern", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get placeholder() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get placeholder' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "placeholder");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set placeholder(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set placeholder' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'placeholder' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "placeholder", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get readOnly() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readOnly' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "readonly");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set readOnly(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set readOnly' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'readOnly' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "readonly", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "readonly");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get required() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get required' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "required");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set required(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set required' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'required' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "required", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "required");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get size() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get size' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["size"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set size(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set size' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'size' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["size"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get step() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get step' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "step");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set step(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set step' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'step' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "step", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["type"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["type"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get defaultValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get defaultValue' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "value");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defaultValue(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set defaultValue' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'defaultValue' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "value", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLInputElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get valueAsDate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get valueAsDate' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol]["valueAsDate"];
+    }
+
+    set valueAsDate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set valueAsDate' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["object"](V, {
+          context: "Failed to set the 'valueAsDate' property on 'HTMLInputElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["valueAsDate"] = V;
+    }
+
+    get valueAsNumber() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get valueAsNumber' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      return esValue[implSymbol]["valueAsNumber"];
+    }
+
+    set valueAsNumber(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set valueAsNumber' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      V = conversions["unrestricted double"](V, {
+        context: "Failed to set the 'valueAsNumber' property on 'HTMLInputElement': The provided value"
+      });
+
+      esValue[implSymbol]["valueAsNumber"] = V;
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get willValidate' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+
+    get selectionStart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectionStart' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      return esValue[implSymbol]["selectionStart"];
+    }
+
+    set selectionStart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectionStart' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["unsigned long"](V, {
+          context: "Failed to set the 'selectionStart' property on 'HTMLInputElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["selectionStart"] = V;
+    }
+
+    get selectionEnd() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get selectionEnd' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      return esValue[implSymbol]["selectionEnd"];
+    }
+
+    set selectionEnd(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set selectionEnd' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["unsigned long"](V, {
+          context: "Failed to set the 'selectionEnd' property on 'HTMLInputElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["selectionEnd"] = V;
+    }
+
+    get selectionDirection() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectionDirection' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      return esValue[implSymbol]["selectionDirection"];
+    }
+
+    set selectionDirection(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectionDirection' called on an object that is not a valid instance of HTMLInputElement."
+        );
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'selectionDirection' property on 'HTMLInputElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["selectionDirection"] = V;
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get useMap() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get useMap' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "usemap");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set useMap(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set useMap' called on an object that is not a valid instance of HTMLInputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'useMap' property on 'HTMLInputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "usemap", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLInputElement.prototype, {
+    stepUp: { enumerable: true },
+    stepDown: { enumerable: true },
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    select: { enumerable: true },
+    setRangeText: { enumerable: true },
+    setSelectionRange: { enumerable: true },
+    accept: { enumerable: true },
+    alt: { enumerable: true },
+    autocomplete: { enumerable: true },
+    autofocus: { enumerable: true },
+    defaultChecked: { enumerable: true },
+    checked: { enumerable: true },
+    dirName: { enumerable: true },
+    disabled: { enumerable: true },
+    form: { enumerable: true },
+    files: { enumerable: true },
+    formNoValidate: { enumerable: true },
+    formTarget: { enumerable: true },
+    indeterminate: { enumerable: true },
+    inputMode: { enumerable: true },
+    list: { enumerable: true },
+    max: { enumerable: true },
+    maxLength: { enumerable: true },
+    min: { enumerable: true },
+    minLength: { enumerable: true },
+    multiple: { enumerable: true },
+    name: { enumerable: true },
+    pattern: { enumerable: true },
+    placeholder: { enumerable: true },
+    readOnly: { enumerable: true },
+    required: { enumerable: true },
+    size: { enumerable: true },
+    src: { enumerable: true },
+    step: { enumerable: true },
+    type: { enumerable: true },
+    defaultValue: { enumerable: true },
+    value: { enumerable: true },
+    valueAsDate: { enumerable: true },
+    valueAsNumber: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    labels: { enumerable: true },
+    selectionStart: { enumerable: true },
+    selectionEnd: { enumerable: true },
+    selectionDirection: { enumerable: true },
+    align: { enumerable: true },
+    useMap: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLInputElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLInputElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLInputElement
+  });
+};
+
+const Impl = require("../nodes/HTMLInputElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLIElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLIElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLIElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,194 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseInteger_helpers_strings = require("../helpers/strings.js").parseInteger;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLLIElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLLIElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLLIElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLLIElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLLIElement before HTMLElement");
+  }
+  class HTMLLIElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLLIElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "value");
+        if (value === null) {
+          return 0;
+        }
+        value = parseInteger_helpers_strings(value);
+        return value !== null && conversions.long(value) === value ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLLIElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'value' property on 'HTMLLIElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "value", String(V));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLLIElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLLIElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLLIElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLLIElement.prototype, {
+    value: { enumerable: true },
+    type: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLLIElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLLIElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLLIElement
+  });
+};
+
+const Impl = require("../nodes/HTMLLIElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLabelElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLabelElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLabelElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,175 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLLabelElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLLabelElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLLabelElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLLabelElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLLabelElement before HTMLElement");
+  }
+  class HTMLLabelElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLLabelElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get htmlFor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get htmlFor' called on an object that is not a valid instance of HTMLLabelElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "for");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set htmlFor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set htmlFor' called on an object that is not a valid instance of HTMLLabelElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'htmlFor' property on 'HTMLLabelElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "for", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get control() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get control' called on an object that is not a valid instance of HTMLLabelElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["control"]);
+    }
+  }
+  Object.defineProperties(HTMLLabelElement.prototype, {
+    form: { enumerable: true },
+    htmlFor: { enumerable: true },
+    control: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLLabelElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLLabelElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLLabelElement
+  });
+};
+
+const Impl = require("../nodes/HTMLLabelElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLegendElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLegendElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLegendElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,164 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLLegendElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLLegendElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLLegendElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLLegendElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLLegendElement before HTMLElement");
+  }
+  class HTMLLegendElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLLegendElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLLegendElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLLegendElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLLegendElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLLegendElement.prototype, {
+    form: { enumerable: true },
+    align: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLLegendElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLLegendElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLLegendElement
+  });
+};
+
+const Impl = require("../nodes/HTMLLegendElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLinkElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLinkElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLLinkElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,496 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLLinkElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLLinkElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLLinkElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLLinkElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLLinkElement before HTMLElement");
+  }
+  class HTMLLinkElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get href() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get href' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "href");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set href(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set href' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'href' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "href", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get crossOrigin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get crossOrigin' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "crossorigin");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set crossOrigin(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set crossOrigin' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'crossOrigin' property on 'HTMLLinkElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "crossorigin", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rel' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rel");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rel' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rel' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rel", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get relList() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get relList' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      return utils.getSameObject(this, "relList", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["relList"]);
+      });
+    }
+
+    set relList(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set relList' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      const Q = esValue["relList"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'relList' is not an object");
+      }
+      Reflect.set(Q, "value", V);
+    }
+
+    get media() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get media' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "media");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set media(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set media' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'media' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "media", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hreflang() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hreflang' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "hreflang");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hreflang(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hreflang' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'hreflang' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "hreflang", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get charset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get charset' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charset");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set charset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set charset' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'charset' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charset", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rev() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rev' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rev");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rev(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rev' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rev' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rev", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "target");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set target(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set target' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'target' property on 'HTMLLinkElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "target", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get sheet() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get sheet' called on an object that is not a valid instance of HTMLLinkElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["sheet"]);
+    }
+  }
+  Object.defineProperties(HTMLLinkElement.prototype, {
+    href: { enumerable: true },
+    crossOrigin: { enumerable: true },
+    rel: { enumerable: true },
+    relList: { enumerable: true },
+    media: { enumerable: true },
+    hreflang: { enumerable: true },
+    type: { enumerable: true },
+    charset: { enumerable: true },
+    rev: { enumerable: true },
+    target: { enumerable: true },
+    sheet: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLLinkElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLLinkElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLLinkElement
+  });
+};
+
+const Impl = require("../nodes/HTMLLinkElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMapElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMapElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMapElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,166 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLMapElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLMapElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLMapElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLMapElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLMapElement before HTMLElement");
+  }
+  class HTMLMapElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLMapElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLMapElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLMapElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get areas() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get areas' called on an object that is not a valid instance of HTMLMapElement.");
+      }
+
+      return utils.getSameObject(this, "areas", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["areas"]);
+      });
+    }
+  }
+  Object.defineProperties(HTMLMapElement.prototype, {
+    name: { enumerable: true },
+    areas: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLMapElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLMapElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLMapElement
+  });
+};
+
+const Impl = require("../nodes/HTMLMapElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMarqueeElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMarqueeElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMarqueeElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,509 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseNonNegativeInteger_helpers_strings = require("../helpers/strings.js").parseNonNegativeInteger;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLMarqueeElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLMarqueeElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLMarqueeElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLMarqueeElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLMarqueeElement before HTMLElement");
+  }
+  class HTMLMarqueeElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get behavior() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get behavior' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "behavior");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set behavior(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set behavior' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'behavior' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "behavior", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get bgColor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bgColor' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "bgcolor");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set bgColor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set bgColor' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'bgColor' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "bgcolor", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get direction() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get direction' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "direction");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set direction(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set direction' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'direction' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "direction", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "height");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'height' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "height", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hspace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hspace' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "hspace");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hspace(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hspace' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'hspace' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "hspace", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get scrollAmount() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get scrollAmount' called on an object that is not a valid instance of HTMLMarqueeElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "scrollamount");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set scrollAmount(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set scrollAmount' called on an object that is not a valid instance of HTMLMarqueeElement."
+        );
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'scrollAmount' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "scrollamount", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get scrollDelay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get scrollDelay' called on an object that is not a valid instance of HTMLMarqueeElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "scrolldelay");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set scrollDelay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set scrollDelay' called on an object that is not a valid instance of HTMLMarqueeElement."
+        );
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'scrollDelay' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "scrolldelay", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get trueSpeed() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get trueSpeed' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "truespeed");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set trueSpeed(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set trueSpeed' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'trueSpeed' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "truespeed", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "truespeed");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vspace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vspace' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "vspace");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vspace(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vspace' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'vspace' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "vspace", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLMarqueeElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLMarqueeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLMarqueeElement.prototype, {
+    behavior: { enumerable: true },
+    bgColor: { enumerable: true },
+    direction: { enumerable: true },
+    height: { enumerable: true },
+    hspace: { enumerable: true },
+    scrollAmount: { enumerable: true },
+    scrollDelay: { enumerable: true },
+    trueSpeed: { enumerable: true },
+    vspace: { enumerable: true },
+    width: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLMarqueeElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLMarqueeElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLMarqueeElement
+  });
+};
+
+const Impl = require("../nodes/HTMLMarqueeElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMediaElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMediaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMediaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,802 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const TextTrackKind = require("./TextTrackKind.js");
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLMediaElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLMediaElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLMediaElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLMediaElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLMediaElement before HTMLElement");
+  }
+  class HTMLMediaElement extends globalObject.HTMLElement {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    load() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'load' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol].load();
+    }
+
+    canPlayType(type) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'canPlayType' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'canPlayType' on 'HTMLMediaElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'canPlayType' on 'HTMLMediaElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].canPlayType(...args));
+    }
+
+    play() {
+      try {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+        if (!exports.is(esValue)) {
+          throw new TypeError("'play' called on an object that is not a valid instance of HTMLMediaElement.");
+        }
+
+        return utils.tryWrapperForImpl(esValue[implSymbol].play());
+      } catch (e) {
+        return Promise.reject(e);
+      }
+    }
+
+    pause() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'pause' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol].pause();
+    }
+
+    addTextTrack(kind) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'addTextTrack' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'addTextTrack' on 'HTMLMediaElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = TextTrackKind.convert(curArg, {
+          context: "Failed to execute 'addTextTrack' on 'HTMLMediaElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'addTextTrack' on 'HTMLMediaElement': parameter 2"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'addTextTrack' on 'HTMLMediaElement': parameter 3"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].addTextTrack(...args));
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLMediaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get currentSrc() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get currentSrc' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["currentSrc"];
+    }
+
+    get crossOrigin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get crossOrigin' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "crossorigin");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set crossOrigin(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set crossOrigin' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'crossOrigin' property on 'HTMLMediaElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "crossorigin", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get networkState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get networkState' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["networkState"];
+    }
+
+    get preload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get preload' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "preload");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set preload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set preload' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'preload' property on 'HTMLMediaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "preload", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get buffered() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get buffered' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["buffered"]);
+    }
+
+    get readyState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readyState' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["readyState"];
+    }
+
+    get seeking() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get seeking' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["seeking"];
+    }
+
+    get currentTime() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get currentTime' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["currentTime"];
+    }
+
+    set currentTime(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set currentTime' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'currentTime' property on 'HTMLMediaElement': The provided value"
+      });
+
+      esValue[implSymbol]["currentTime"] = V;
+    }
+
+    get duration() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get duration' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["duration"];
+    }
+
+    get paused() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get paused' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["paused"];
+    }
+
+    get defaultPlaybackRate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get defaultPlaybackRate' called on an object that is not a valid instance of HTMLMediaElement."
+        );
+      }
+
+      return esValue[implSymbol]["defaultPlaybackRate"];
+    }
+
+    set defaultPlaybackRate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set defaultPlaybackRate' called on an object that is not a valid instance of HTMLMediaElement."
+        );
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'defaultPlaybackRate' property on 'HTMLMediaElement': The provided value"
+      });
+
+      esValue[implSymbol]["defaultPlaybackRate"] = V;
+    }
+
+    get playbackRate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get playbackRate' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["playbackRate"];
+    }
+
+    set playbackRate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set playbackRate' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'playbackRate' property on 'HTMLMediaElement': The provided value"
+      });
+
+      esValue[implSymbol]["playbackRate"] = V;
+    }
+
+    get played() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get played' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["played"]);
+    }
+
+    get seekable() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get seekable' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["seekable"]);
+    }
+
+    get ended() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ended' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["ended"];
+    }
+
+    get autoplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get autoplay' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "autoplay");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autoplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set autoplay' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'autoplay' property on 'HTMLMediaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "autoplay", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "autoplay");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get loop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get loop' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "loop");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set loop(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set loop' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'loop' property on 'HTMLMediaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "loop", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "loop");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get controls() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get controls' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "controls");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set controls(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set controls' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'controls' property on 'HTMLMediaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "controls", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "controls");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get volume() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get volume' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["volume"];
+    }
+
+    set volume(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set volume' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'volume' property on 'HTMLMediaElement': The provided value"
+      });
+
+      esValue[implSymbol]["volume"] = V;
+    }
+
+    get muted() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get muted' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return esValue[implSymbol]["muted"];
+    }
+
+    set muted(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set muted' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'muted' property on 'HTMLMediaElement': The provided value"
+      });
+
+      esValue[implSymbol]["muted"] = V;
+    }
+
+    get defaultMuted() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get defaultMuted' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "muted");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defaultMuted(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set defaultMuted' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'defaultMuted' property on 'HTMLMediaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "muted", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "muted");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get audioTracks() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get audioTracks' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return utils.getSameObject(this, "audioTracks", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["audioTracks"]);
+      });
+    }
+
+    get videoTracks() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get videoTracks' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return utils.getSameObject(this, "videoTracks", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["videoTracks"]);
+      });
+    }
+
+    get textTracks() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get textTracks' called on an object that is not a valid instance of HTMLMediaElement.");
+      }
+
+      return utils.getSameObject(this, "textTracks", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["textTracks"]);
+      });
+    }
+  }
+  Object.defineProperties(HTMLMediaElement.prototype, {
+    load: { enumerable: true },
+    canPlayType: { enumerable: true },
+    play: { enumerable: true },
+    pause: { enumerable: true },
+    addTextTrack: { enumerable: true },
+    src: { enumerable: true },
+    currentSrc: { enumerable: true },
+    crossOrigin: { enumerable: true },
+    networkState: { enumerable: true },
+    preload: { enumerable: true },
+    buffered: { enumerable: true },
+    readyState: { enumerable: true },
+    seeking: { enumerable: true },
+    currentTime: { enumerable: true },
+    duration: { enumerable: true },
+    paused: { enumerable: true },
+    defaultPlaybackRate: { enumerable: true },
+    playbackRate: { enumerable: true },
+    played: { enumerable: true },
+    seekable: { enumerable: true },
+    ended: { enumerable: true },
+    autoplay: { enumerable: true },
+    loop: { enumerable: true },
+    controls: { enumerable: true },
+    volume: { enumerable: true },
+    muted: { enumerable: true },
+    defaultMuted: { enumerable: true },
+    audioTracks: { enumerable: true },
+    videoTracks: { enumerable: true },
+    textTracks: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLMediaElement", configurable: true },
+    NETWORK_EMPTY: { value: 0, enumerable: true },
+    NETWORK_IDLE: { value: 1, enumerable: true },
+    NETWORK_LOADING: { value: 2, enumerable: true },
+    NETWORK_NO_SOURCE: { value: 3, enumerable: true },
+    HAVE_NOTHING: { value: 0, enumerable: true },
+    HAVE_METADATA: { value: 1, enumerable: true },
+    HAVE_CURRENT_DATA: { value: 2, enumerable: true },
+    HAVE_FUTURE_DATA: { value: 3, enumerable: true },
+    HAVE_ENOUGH_DATA: { value: 4, enumerable: true }
+  });
+  Object.defineProperties(HTMLMediaElement, {
+    NETWORK_EMPTY: { value: 0, enumerable: true },
+    NETWORK_IDLE: { value: 1, enumerable: true },
+    NETWORK_LOADING: { value: 2, enumerable: true },
+    NETWORK_NO_SOURCE: { value: 3, enumerable: true },
+    HAVE_NOTHING: { value: 0, enumerable: true },
+    HAVE_METADATA: { value: 1, enumerable: true },
+    HAVE_CURRENT_DATA: { value: 2, enumerable: true },
+    HAVE_FUTURE_DATA: { value: 3, enumerable: true },
+    HAVE_ENOUGH_DATA: { value: 4, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLMediaElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLMediaElement
+  });
+};
+
+const Impl = require("../nodes/HTMLMediaElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMenuElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMenuElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMenuElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,156 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLMenuElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLMenuElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLMenuElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLMenuElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLMenuElement before HTMLElement");
+  }
+  class HTMLMenuElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get compact() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get compact' called on an object that is not a valid instance of HTMLMenuElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "compact");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set compact(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set compact' called on an object that is not a valid instance of HTMLMenuElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'compact' property on 'HTMLMenuElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "compact", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "compact");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLMenuElement.prototype, {
+    compact: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLMenuElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLMenuElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLMenuElement
+  });
+};
+
+const Impl = require("../nodes/HTMLMenuElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMetaElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMetaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMetaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,261 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLMetaElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLMetaElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLMetaElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLMetaElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLMetaElement before HTMLElement");
+  }
+  class HTMLMetaElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLMetaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get httpEquiv() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get httpEquiv' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "http-equiv");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set httpEquiv(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set httpEquiv' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'httpEquiv' property on 'HTMLMetaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "http-equiv", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get content() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get content' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "content");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set content(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set content' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'content' property on 'HTMLMetaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "content", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get scheme() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scheme' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "scheme");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set scheme(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set scheme' called on an object that is not a valid instance of HTMLMetaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'scheme' property on 'HTMLMetaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "scheme", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLMetaElement.prototype, {
+    name: { enumerable: true },
+    httpEquiv: { enumerable: true },
+    content: { enumerable: true },
+    scheme: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLMetaElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLMetaElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLMetaElement
+  });
+};
+
+const Impl = require("../nodes/HTMLMetaElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMeterElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMeterElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLMeterElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,338 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLMeterElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLMeterElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLMeterElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLMeterElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLMeterElement before HTMLElement");
+  }
+  class HTMLMeterElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'value' property on 'HTMLMeterElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get min() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get min' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["min"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set min(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set min' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'min' property on 'HTMLMeterElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["min"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get max() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get max' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["max"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set max(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set max' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'max' property on 'HTMLMeterElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["max"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get low() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get low' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["low"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set low(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set low' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'low' property on 'HTMLMeterElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["low"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get high() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get high' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["high"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set high(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set high' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'high' property on 'HTMLMeterElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["high"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get optimum() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get optimum' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["optimum"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set optimum(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set optimum' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'optimum' property on 'HTMLMeterElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["optimum"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLMeterElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+  }
+  Object.defineProperties(HTMLMeterElement.prototype, {
+    value: { enumerable: true },
+    min: { enumerable: true },
+    max: { enumerable: true },
+    low: { enumerable: true },
+    high: { enumerable: true },
+    optimum: { enumerable: true },
+    labels: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLMeterElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLMeterElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLMeterElement
+  });
+};
+
+const Impl = require("../nodes/HTMLMeterElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLModElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLModElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLModElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,202 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLModElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLModElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLModElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLModElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLModElement before HTMLElement");
+  }
+  class HTMLModElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get cite() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cite' called on an object that is not a valid instance of HTMLModElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "cite");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set cite(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cite' called on an object that is not a valid instance of HTMLModElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'cite' property on 'HTMLModElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "cite", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get dateTime() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dateTime' called on an object that is not a valid instance of HTMLModElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "datetime");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set dateTime(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set dateTime' called on an object that is not a valid instance of HTMLModElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'dateTime' property on 'HTMLModElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "datetime", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLModElement.prototype, {
+    cite: { enumerable: true },
+    dateTime: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLModElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLModElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLModElement
+  });
+};
+
+const Impl = require("../nodes/HTMLModElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOListElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,266 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLOListElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLOListElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLOListElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLOListElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLOListElement before HTMLElement");
+  }
+  class HTMLOListElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get reversed() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get reversed' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "reversed");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set reversed(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set reversed' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'reversed' property on 'HTMLOListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "reversed", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "reversed");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get start() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get start' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["start"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set start(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set start' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'start' property on 'HTMLOListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["start"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLOListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get compact() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get compact' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "compact");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set compact(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set compact' called on an object that is not a valid instance of HTMLOListElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'compact' property on 'HTMLOListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "compact", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "compact");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLOListElement.prototype, {
+    reversed: { enumerable: true },
+    start: { enumerable: true },
+    type: { enumerable: true },
+    compact: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLOListElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLOListElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLOListElement
+  });
+};
+
+const Impl = require("../nodes/HTMLOListElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLObjectElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLObjectElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLObjectElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,839 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseNonNegativeInteger_helpers_strings = require("../helpers/strings.js").parseNonNegativeInteger;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLObjectElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLObjectElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLObjectElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLObjectElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLObjectElement before HTMLElement");
+  }
+  class HTMLObjectElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reportValidity' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLObjectElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLObjectElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLObjectElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    get data() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get data' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "data");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set data(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set data' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'data' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "data", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get useMap() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get useMap' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "usemap");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set useMap(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set useMap' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'useMap' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "usemap", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "height");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'height' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "height", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get contentDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get contentDocument' called on an object that is not a valid instance of HTMLObjectElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["contentDocument"]);
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get willValidate' called on an object that is not a valid instance of HTMLObjectElement."
+        );
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLObjectElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get archive() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get archive' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "archive");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set archive(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set archive' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'archive' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "archive", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get code() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get code' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "code");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set code(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set code' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'code' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "code", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get declare() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get declare' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "declare");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set declare(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set declare' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'declare' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "declare", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "declare");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get hspace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hspace' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "hspace");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set hspace(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set hspace' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'hspace' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "hspace", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get standby() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get standby' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "standby");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set standby(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set standby' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'standby' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "standby", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vspace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vspace' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "vspace");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vspace(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vspace' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'vspace' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "vspace", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get codeBase() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get codeBase' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "codebase");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set codeBase(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set codeBase' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'codeBase' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "codebase", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get codeType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get codeType' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "codetype");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set codeType(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set codeType' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'codeType' property on 'HTMLObjectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "codetype", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get border() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get border' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "border");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set border(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set border' called on an object that is not a valid instance of HTMLObjectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'border' property on 'HTMLObjectElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "border", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLObjectElement.prototype, {
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    data: { enumerable: true },
+    type: { enumerable: true },
+    name: { enumerable: true },
+    useMap: { enumerable: true },
+    form: { enumerable: true },
+    width: { enumerable: true },
+    height: { enumerable: true },
+    contentDocument: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    align: { enumerable: true },
+    archive: { enumerable: true },
+    code: { enumerable: true },
+    declare: { enumerable: true },
+    hspace: { enumerable: true },
+    standby: { enumerable: true },
+    vspace: { enumerable: true },
+    codeBase: { enumerable: true },
+    codeType: { enumerable: true },
+    border: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLObjectElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLObjectElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLObjectElement
+  });
+};
+
+const Impl = require("../nodes/HTMLObjectElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptGroupElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptGroupElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptGroupElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,192 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLOptGroupElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLOptGroupElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLOptGroupElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLOptGroupElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLOptGroupElement before HTMLElement");
+  }
+  class HTMLOptGroupElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLOptGroupElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLOptGroupElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLOptGroupElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get label() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get label' called on an object that is not a valid instance of HTMLOptGroupElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "label");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set label(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set label' called on an object that is not a valid instance of HTMLOptGroupElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'label' property on 'HTMLOptGroupElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "label", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLOptGroupElement.prototype, {
+    disabled: { enumerable: true },
+    label: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLOptGroupElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLOptGroupElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLOptGroupElement
+  });
+};
+
+const Impl = require("../nodes/HTMLOptGroupElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptionElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptionElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptionElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,351 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLOptionElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLOptionElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLOptionElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLOptionElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLOptionElement before HTMLElement");
+  }
+  class HTMLOptionElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLOptionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get label() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get label' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["label"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set label(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set label' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'label' property on 'HTMLOptionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["label"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get defaultSelected() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get defaultSelected' called on an object that is not a valid instance of HTMLOptionElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "selected");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defaultSelected(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set defaultSelected' called on an object that is not a valid instance of HTMLOptionElement."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'defaultSelected' property on 'HTMLOptionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "selected", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "selected");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get selected() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get selected' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      return esValue[implSymbol]["selected"];
+    }
+
+    set selected(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set selected' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'selected' property on 'HTMLOptionElement': The provided value"
+      });
+
+      esValue[implSymbol]["selected"] = V;
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLOptionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get text() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get text' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["text"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set text(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set text' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'text' property on 'HTMLOptionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["text"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get index() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get index' called on an object that is not a valid instance of HTMLOptionElement.");
+      }
+
+      return esValue[implSymbol]["index"];
+    }
+  }
+  Object.defineProperties(HTMLOptionElement.prototype, {
+    disabled: { enumerable: true },
+    form: { enumerable: true },
+    label: { enumerable: true },
+    defaultSelected: { enumerable: true },
+    selected: { enumerable: true },
+    value: { enumerable: true },
+    text: { enumerable: true },
+    index: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLOptionElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLOptionElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLOptionElement
+  });
+};
+
+const Impl = require("../nodes/HTMLOptionElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptionsCollection.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptionsCollection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOptionsCollection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,533 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLOptionElement = require("./HTMLOptionElement.js");
+const HTMLOptGroupElement = require("./HTMLOptGroupElement.js");
+const HTMLElement = require("./HTMLElement.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLCollection = require("./HTMLCollection.js");
+
+const interfaceName = "HTMLOptionsCollection";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLOptionsCollection'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLOptionsCollection"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLOptionsCollection is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+function makeProxy(wrapper, globalObject) {
+  let proxyHandler = proxyHandlerCache.get(globalObject);
+  if (proxyHandler === undefined) {
+    proxyHandler = new ProxyHandler(globalObject);
+    proxyHandlerCache.set(globalObject, proxyHandler);
+  }
+  return new Proxy(wrapper, proxyHandler);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLCollection._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = makeProxy(wrapper, globalObject);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = makeProxy(wrapper, globalObject);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLCollection === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLOptionsCollection before HTMLCollection");
+  }
+  class HTMLOptionsCollection extends globalObject.HTMLCollection {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    add(element) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'add' called on an object that is not a valid instance of HTMLOptionsCollection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'add' on 'HTMLOptionsCollection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (HTMLOptionElement.is(curArg) || HTMLOptGroupElement.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          throw new TypeError(
+            "Failed to execute 'add' on 'HTMLOptionsCollection': parameter 1" + " is not of any supported type."
+          );
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            if (HTMLElement.is(curArg)) {
+              curArg = utils.implForWrapper(curArg);
+            } else if (typeof curArg === "number") {
+              curArg = conversions["long"](curArg, {
+                context: "Failed to execute 'add' on 'HTMLOptionsCollection': parameter 2"
+              });
+            } else {
+              curArg = conversions["long"](curArg, {
+                context: "Failed to execute 'add' on 'HTMLOptionsCollection': parameter 2"
+              });
+            }
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].add(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    remove(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'remove' called on an object that is not a valid instance of HTMLOptionsCollection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'remove' on 'HTMLOptionsCollection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["long"](curArg, {
+          context: "Failed to execute 'remove' on 'HTMLOptionsCollection': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].remove(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of HTMLOptionsCollection.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["length"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set length(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set length' called on an object that is not a valid instance of HTMLOptionsCollection.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'length' property on 'HTMLOptionsCollection': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["length"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get selectedIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectedIndex' called on an object that is not a valid instance of HTMLOptionsCollection."
+        );
+      }
+
+      return esValue[implSymbol]["selectedIndex"];
+    }
+
+    set selectedIndex(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectedIndex' called on an object that is not a valid instance of HTMLOptionsCollection."
+        );
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'selectedIndex' property on 'HTMLOptionsCollection': The provided value"
+      });
+
+      esValue[implSymbol]["selectedIndex"] = V;
+    }
+  }
+  Object.defineProperties(HTMLOptionsCollection.prototype, {
+    add: { enumerable: true },
+    remove: { enumerable: true },
+    length: { enumerable: true },
+    selectedIndex: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLOptionsCollection", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLOptionsCollection;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLOptionsCollection
+  });
+};
+
+const proxyHandlerCache = new WeakMap();
+class ProxyHandler {
+  constructor(globalObject) {
+    this._globalObject = globalObject;
+  }
+
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  }
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  }
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of target[implSymbol][utils.supportedPropertyNames]) {
+      if (!(key in target)) {
+        keys.add(`${key}`);
+      }
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  }
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: true,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    const namedValue = target[implSymbol].namedItem(P);
+
+    if (namedValue !== null && !(P in target) && !ignoreNamedProps) {
+      return {
+        writable: false,
+        enumerable: true,
+        configurable: true,
+        value: utils.tryWrapperForImpl(namedValue)
+      };
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  }
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+      const globalObject = this._globalObject;
+
+      if (utils.isArrayIndexPropName(P)) {
+        const index = P >>> 0;
+        let indexedValue = V;
+
+        if (indexedValue === null || indexedValue === undefined) {
+          indexedValue = null;
+        } else {
+          indexedValue = HTMLOptionElement.convert(indexedValue, {
+            context: "Failed to set the " + index + " property on 'HTMLOptionsCollection': The provided value"
+          });
+        }
+
+        ceReactionsPreSteps_helpers_custom_elements(globalObject);
+        try {
+          const creating = !(target[implSymbol].item(index) !== null);
+          if (creating) {
+            target[implSymbol][utils.indexedSetNew](index, indexedValue);
+          } else {
+            target[implSymbol][utils.indexedSetExisting](index, indexedValue);
+          }
+        } finally {
+          ceReactionsPostSteps_helpers_custom_elements(globalObject);
+        }
+
+        return true;
+      }
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: true,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  }
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    const globalObject = this._globalObject;
+
+    if (utils.isArrayIndexPropName(P)) {
+      if (desc.get || desc.set) {
+        return false;
+      }
+
+      const index = P >>> 0;
+      let indexedValue = desc.value;
+
+      if (indexedValue === null || indexedValue === undefined) {
+        indexedValue = null;
+      } else {
+        indexedValue = HTMLOptionElement.convert(indexedValue, {
+          context: "Failed to set the " + index + " property on 'HTMLOptionsCollection': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const creating = !(target[implSymbol].item(index) !== null);
+        if (creating) {
+          target[implSymbol][utils.indexedSetNew](index, indexedValue);
+        } else {
+          target[implSymbol][utils.indexedSetExisting](index, indexedValue);
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+
+      return true;
+    }
+    if (!utils.hasOwn(target, P)) {
+      const creating = !(target[implSymbol].namedItem(P) !== null);
+      if (!creating) {
+        return false;
+      }
+    }
+    return Reflect.defineProperty(target, P, desc);
+  }
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    const globalObject = this._globalObject;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    if (target[implSymbol].namedItem(P) !== null && !(P in target)) {
+      return false;
+    }
+
+    return Reflect.deleteProperty(target, P);
+  }
+
+  preventExtensions() {
+    return false;
+  }
+}
+
+const Impl = require("../nodes/HTMLOptionsCollection-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOutputElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOutputElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLOutputElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,371 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLOutputElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLOutputElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLOutputElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLOutputElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLOutputElement before HTMLElement");
+  }
+  class HTMLOutputElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reportValidity' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLOutputElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLOutputElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLOutputElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    get htmlFor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get htmlFor' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return utils.getSameObject(this, "htmlFor", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["htmlFor"]);
+      });
+    }
+
+    set htmlFor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set htmlFor' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      const Q = esValue["htmlFor"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'htmlFor' is not an object");
+      }
+      Reflect.set(Q, "value", V);
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLOutputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+
+    get defaultValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get defaultValue' called on an object that is not a valid instance of HTMLOutputElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["defaultValue"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defaultValue(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set defaultValue' called on an object that is not a valid instance of HTMLOutputElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'defaultValue' property on 'HTMLOutputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["defaultValue"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLOutputElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get willValidate' called on an object that is not a valid instance of HTMLOutputElement."
+        );
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLOutputElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLOutputElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+  }
+  Object.defineProperties(HTMLOutputElement.prototype, {
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    htmlFor: { enumerable: true },
+    form: { enumerable: true },
+    name: { enumerable: true },
+    type: { enumerable: true },
+    defaultValue: { enumerable: true },
+    value: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    labels: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLOutputElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLOutputElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLOutputElement
+  });
+};
+
+const Impl = require("../nodes/HTMLOutputElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLParagraphElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLParagraphElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLParagraphElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLParagraphElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLParagraphElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLParagraphElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLParagraphElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLParagraphElement before HTMLElement");
+  }
+  class HTMLParagraphElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLParagraphElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLParagraphElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLParagraphElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLParagraphElement.prototype, {
+    align: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLParagraphElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLParagraphElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLParagraphElement
+  });
+};
+
+const Impl = require("../nodes/HTMLParagraphElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLParamElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLParamElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLParamElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,261 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLParamElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLParamElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLParamElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLParamElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLParamElement before HTMLElement");
+  }
+  class HTMLParamElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLParamElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "value");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLParamElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "value", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLParamElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get valueType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get valueType' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "valuetype");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set valueType(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set valueType' called on an object that is not a valid instance of HTMLParamElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'valueType' property on 'HTMLParamElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "valuetype", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLParamElement.prototype, {
+    name: { enumerable: true },
+    value: { enumerable: true },
+    type: { enumerable: true },
+    valueType: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLParamElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLParamElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLParamElement
+  });
+};
+
+const Impl = require("../nodes/HTMLParamElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLPictureElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLPictureElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLPictureElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,115 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLPictureElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLPictureElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLPictureElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLPictureElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLPictureElement before HTMLElement");
+  }
+  class HTMLPictureElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+  }
+  Object.defineProperties(HTMLPictureElement.prototype, {
+    [Symbol.toStringTag]: { value: "HTMLPictureElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLPictureElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLPictureElement
+  });
+};
+
+const Impl = require("../nodes/HTMLPictureElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLPreElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLPreElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLPreElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,158 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseInteger_helpers_strings = require("../helpers/strings.js").parseInteger;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLPreElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLPreElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLPreElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLPreElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLPreElement before HTMLElement");
+  }
+  class HTMLPreElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLPreElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "width");
+        if (value === null) {
+          return 0;
+        }
+        value = parseInteger_helpers_strings(value);
+        return value !== null && conversions.long(value) === value ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLPreElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'width' property on 'HTMLPreElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", String(V));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLPreElement.prototype, {
+    width: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLPreElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLPreElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLPreElement
+  });
+};
+
+const Impl = require("../nodes/HTMLPreElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLProgressElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLProgressElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLProgressElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,209 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLProgressElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLProgressElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLProgressElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLProgressElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLProgressElement before HTMLElement");
+  }
+  class HTMLProgressElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLProgressElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLProgressElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'value' property on 'HTMLProgressElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get max() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get max' called on an object that is not a valid instance of HTMLProgressElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["max"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set max(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set max' called on an object that is not a valid instance of HTMLProgressElement.");
+      }
+
+      V = conversions["double"](V, {
+        context: "Failed to set the 'max' property on 'HTMLProgressElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["max"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get position() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get position' called on an object that is not a valid instance of HTMLProgressElement.");
+      }
+
+      return esValue[implSymbol]["position"];
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLProgressElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+  }
+  Object.defineProperties(HTMLProgressElement.prototype, {
+    value: { enumerable: true },
+    max: { enumerable: true },
+    position: { enumerable: true },
+    labels: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLProgressElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLProgressElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLProgressElement
+  });
+};
+
+const Impl = require("../nodes/HTMLProgressElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLQuoteElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLQuoteElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLQuoteElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,166 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLQuoteElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLQuoteElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLQuoteElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLQuoteElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLQuoteElement before HTMLElement");
+  }
+  class HTMLQuoteElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get cite() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cite' called on an object that is not a valid instance of HTMLQuoteElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "cite");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set cite(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cite' called on an object that is not a valid instance of HTMLQuoteElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'cite' property on 'HTMLQuoteElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "cite", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLQuoteElement.prototype, {
+    cite: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLQuoteElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLQuoteElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLQuoteElement
+  });
+};
+
+const Impl = require("../nodes/HTMLQuoteElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLScriptElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLScriptElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLScriptElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,424 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLScriptElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLScriptElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLScriptElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLScriptElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLScriptElement before HTMLElement");
+  }
+  class HTMLScriptElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get defer() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get defer' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "defer");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defer(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set defer' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'defer' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "defer", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "defer");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get crossOrigin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get crossOrigin' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "crossorigin");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set crossOrigin(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set crossOrigin' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'crossOrigin' property on 'HTMLScriptElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "crossorigin", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get text() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get text' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["text"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set text(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set text' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'text' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["text"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get charset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get charset' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charset");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set charset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set charset' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'charset' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charset", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get event() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get event' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "event");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set event(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set event' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'event' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "event", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get htmlFor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get htmlFor' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "for");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set htmlFor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set htmlFor' called on an object that is not a valid instance of HTMLScriptElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'htmlFor' property on 'HTMLScriptElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "for", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLScriptElement.prototype, {
+    src: { enumerable: true },
+    type: { enumerable: true },
+    defer: { enumerable: true },
+    crossOrigin: { enumerable: true },
+    text: { enumerable: true },
+    charset: { enumerable: true },
+    event: { enumerable: true },
+    htmlFor: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLScriptElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLScriptElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLScriptElement
+  });
+};
+
+const Impl = require("../nodes/HTMLScriptElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSelectElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSelectElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSelectElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,957 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const HTMLOptionElement = require("./HTMLOptionElement.js");
+const HTMLOptGroupElement = require("./HTMLOptGroupElement.js");
+const HTMLElement = require("./HTMLElement.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseNonNegativeInteger_helpers_strings = require("../helpers/strings.js").parseNonNegativeInteger;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "HTMLSelectElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLSelectElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLSelectElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLSelectElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+function makeProxy(wrapper, globalObject) {
+  let proxyHandler = proxyHandlerCache.get(globalObject);
+  if (proxyHandler === undefined) {
+    proxyHandler = new ProxyHandler(globalObject);
+    proxyHandlerCache.set(globalObject, proxyHandler);
+  }
+  return new Proxy(wrapper, proxyHandler);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = makeProxy(wrapper, globalObject);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = makeProxy(wrapper, globalObject);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLSelectElement before HTMLElement");
+  }
+  class HTMLSelectElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'HTMLSelectElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'HTMLSelectElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    namedItem(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'namedItem' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'namedItem' on 'HTMLSelectElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'namedItem' on 'HTMLSelectElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].namedItem(...args));
+    }
+
+    add(element) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'add' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'add' on 'HTMLSelectElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (HTMLOptionElement.is(curArg) || HTMLOptGroupElement.is(curArg)) {
+          curArg = utils.implForWrapper(curArg);
+        } else {
+          throw new TypeError(
+            "Failed to execute 'add' on 'HTMLSelectElement': parameter 1" + " is not of any supported type."
+          );
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            if (HTMLElement.is(curArg)) {
+              curArg = utils.implForWrapper(curArg);
+            } else if (typeof curArg === "number") {
+              curArg = conversions["long"](curArg, {
+                context: "Failed to execute 'add' on 'HTMLSelectElement': parameter 2"
+              });
+            } else {
+              curArg = conversions["long"](curArg, {
+                context: "Failed to execute 'add' on 'HTMLSelectElement': parameter 2"
+              });
+            }
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].add(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    remove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'remove' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+      const args = [];
+      switch (arguments.length) {
+        case 0:
+          break;
+        default: {
+          let curArg = arguments[0];
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'remove' on 'HTMLSelectElement': parameter 1"
+          });
+          args.push(curArg);
+        }
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].remove(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'reportValidity' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLSelectElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLSelectElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLSelectElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    get autofocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get autofocus' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "autofocus");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autofocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set autofocus' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'autofocus' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "autofocus", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "autofocus");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get multiple() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get multiple' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "multiple");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set multiple(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set multiple' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'multiple' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "multiple", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "multiple");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get required() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get required' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "required");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set required(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set required' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'required' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "required", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "required");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get size() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get size' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "size");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set size(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set size' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'size' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "size", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+
+    get options() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get options' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return utils.getSameObject(this, "options", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["options"]);
+      });
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["length"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set length(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set length' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'length' property on 'HTMLSelectElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["length"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get selectedOptions() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectedOptions' called on an object that is not a valid instance of HTMLSelectElement."
+        );
+      }
+
+      return utils.getSameObject(this, "selectedOptions", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["selectedOptions"]);
+      });
+    }
+
+    get selectedIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectedIndex' called on an object that is not a valid instance of HTMLSelectElement."
+        );
+      }
+
+      return esValue[implSymbol]["selectedIndex"];
+    }
+
+    set selectedIndex(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectedIndex' called on an object that is not a valid instance of HTMLSelectElement."
+        );
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'selectedIndex' property on 'HTMLSelectElement': The provided value"
+      });
+
+      esValue[implSymbol]["selectedIndex"] = V;
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return esValue[implSymbol]["value"];
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLSelectElement': The provided value"
+      });
+
+      esValue[implSymbol]["value"] = V;
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get willValidate' called on an object that is not a valid instance of HTMLSelectElement."
+        );
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLSelectElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLSelectElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+  }
+  Object.defineProperties(HTMLSelectElement.prototype, {
+    item: { enumerable: true },
+    namedItem: { enumerable: true },
+    add: { enumerable: true },
+    remove: { enumerable: true },
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    autofocus: { enumerable: true },
+    disabled: { enumerable: true },
+    form: { enumerable: true },
+    multiple: { enumerable: true },
+    name: { enumerable: true },
+    required: { enumerable: true },
+    size: { enumerable: true },
+    type: { enumerable: true },
+    options: { enumerable: true },
+    length: { enumerable: true },
+    selectedOptions: { enumerable: true },
+    selectedIndex: { enumerable: true },
+    value: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    labels: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLSelectElement", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLSelectElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLSelectElement
+  });
+};
+
+const proxyHandlerCache = new WeakMap();
+class ProxyHandler {
+  constructor(globalObject) {
+    this._globalObject = globalObject;
+  }
+
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  }
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  }
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  }
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: true,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  }
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+      const globalObject = this._globalObject;
+
+      if (utils.isArrayIndexPropName(P)) {
+        const index = P >>> 0;
+        let indexedValue = V;
+
+        if (indexedValue === null || indexedValue === undefined) {
+          indexedValue = null;
+        } else {
+          indexedValue = HTMLOptionElement.convert(indexedValue, {
+            context: "Failed to set the " + index + " property on 'HTMLSelectElement': The provided value"
+          });
+        }
+
+        ceReactionsPreSteps_helpers_custom_elements(globalObject);
+        try {
+          const creating = !(target[implSymbol].item(index) !== null);
+          if (creating) {
+            target[implSymbol][utils.indexedSetNew](index, indexedValue);
+          } else {
+            target[implSymbol][utils.indexedSetExisting](index, indexedValue);
+          }
+        } finally {
+          ceReactionsPostSteps_helpers_custom_elements(globalObject);
+        }
+
+        return true;
+      }
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: true,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  }
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    const globalObject = this._globalObject;
+
+    if (utils.isArrayIndexPropName(P)) {
+      if (desc.get || desc.set) {
+        return false;
+      }
+
+      const index = P >>> 0;
+      let indexedValue = desc.value;
+
+      if (indexedValue === null || indexedValue === undefined) {
+        indexedValue = null;
+      } else {
+        indexedValue = HTMLOptionElement.convert(indexedValue, {
+          context: "Failed to set the " + index + " property on 'HTMLSelectElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const creating = !(target[implSymbol].item(index) !== null);
+        if (creating) {
+          target[implSymbol][utils.indexedSetNew](index, indexedValue);
+        } else {
+          target[implSymbol][utils.indexedSetExisting](index, indexedValue);
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+
+      return true;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  }
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    const globalObject = this._globalObject;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  }
+
+  preventExtensions() {
+    return false;
+  }
+}
+
+const Impl = require("../nodes/HTMLSelectElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSlotElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSlotElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSlotElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,188 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const AssignedNodesOptions = require("./AssignedNodesOptions.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLSlotElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLSlotElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLSlotElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLSlotElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLSlotElement before HTMLElement");
+  }
+  class HTMLSlotElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    assignedNodes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'assignedNodes' called on an object that is not a valid instance of HTMLSlotElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = AssignedNodesOptions.convert(curArg, {
+          context: "Failed to execute 'assignedNodes' on 'HTMLSlotElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].assignedNodes(...args));
+    }
+
+    assignedElements() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'assignedElements' called on an object that is not a valid instance of HTMLSlotElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = AssignedNodesOptions.convert(curArg, {
+          context: "Failed to execute 'assignedElements' on 'HTMLSlotElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].assignedElements(...args));
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLSlotElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLSlotElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLSlotElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLSlotElement.prototype, {
+    assignedNodes: { enumerable: true },
+    assignedElements: { enumerable: true },
+    name: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLSlotElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLSlotElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLSlotElement
+  });
+};
+
+const Impl = require("../nodes/HTMLSlotElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSourceElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSourceElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSourceElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,310 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLSourceElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLSourceElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLSourceElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLSourceElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLSourceElement before HTMLElement");
+  }
+  class HTMLSourceElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLSourceElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLSourceElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get srcset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get srcset' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "srcset");
+        return value === null ? "" : conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set srcset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set srcset' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'srcset' property on 'HTMLSourceElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "srcset", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get sizes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get sizes' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "sizes");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set sizes(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set sizes' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'sizes' property on 'HTMLSourceElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "sizes", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get media() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get media' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "media");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set media(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set media' called on an object that is not a valid instance of HTMLSourceElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'media' property on 'HTMLSourceElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "media", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLSourceElement.prototype, {
+    src: { enumerable: true },
+    type: { enumerable: true },
+    srcset: { enumerable: true },
+    sizes: { enumerable: true },
+    media: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLSourceElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLSourceElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLSourceElement
+  });
+};
+
+const Impl = require("../nodes/HTMLSourceElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSpanElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSpanElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLSpanElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,115 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLSpanElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLSpanElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLSpanElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLSpanElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLSpanElement before HTMLElement");
+  }
+  class HTMLSpanElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+  }
+  Object.defineProperties(HTMLSpanElement.prototype, {
+    [Symbol.toStringTag]: { value: "HTMLSpanElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLSpanElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLSpanElement
+  });
+};
+
+const Impl = require("../nodes/HTMLSpanElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLStyleElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLStyleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLStyleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,200 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLStyleElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLStyleElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLStyleElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLStyleElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLStyleElement before HTMLElement");
+  }
+  class HTMLStyleElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get media() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get media' called on an object that is not a valid instance of HTMLStyleElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "media");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set media(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set media' called on an object that is not a valid instance of HTMLStyleElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'media' property on 'HTMLStyleElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "media", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLStyleElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLStyleElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLStyleElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get sheet() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get sheet' called on an object that is not a valid instance of HTMLStyleElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["sheet"]);
+    }
+  }
+  Object.defineProperties(HTMLStyleElement.prototype, {
+    media: { enumerable: true },
+    type: { enumerable: true },
+    sheet: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLStyleElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLStyleElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLStyleElement
+  });
+};
+
+const Impl = require("../nodes/HTMLStyleElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableCaptionElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableCaptionElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableCaptionElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTableCaptionElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTableCaptionElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTableCaptionElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTableCaptionElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTableCaptionElement before HTMLElement");
+  }
+  class HTMLTableCaptionElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLTableCaptionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLTableCaptionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLTableCaptionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTableCaptionElement.prototype, {
+    align: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTableCaptionElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTableCaptionElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTableCaptionElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTableCaptionElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableCellElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableCellElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableCellElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,635 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTableCellElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTableCellElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTableCellElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTableCellElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTableCellElement before HTMLElement");
+  }
+  class HTMLTableCellElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get colSpan() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get colSpan' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["colSpan"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set colSpan(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set colSpan' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'colSpan' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["colSpan"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rowSpan() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rowSpan' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["rowSpan"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rowSpan(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rowSpan' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'rowSpan' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["rowSpan"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get headers() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get headers' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "headers");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set headers(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set headers' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'headers' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "headers", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get cellIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get cellIndex' called on an object that is not a valid instance of HTMLTableCellElement."
+        );
+      }
+
+      return esValue[implSymbol]["cellIndex"];
+    }
+
+    get scope() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get scope' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["scope"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set scope(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set scope' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'scope' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["scope"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get abbr() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get abbr' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "abbr");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set abbr(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set abbr' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'abbr' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "abbr", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get axis() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get axis' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "axis");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set axis(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set axis' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'axis' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "axis", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "height");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'height' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "height", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get ch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ch' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "char");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set ch(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ch' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'ch' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "char", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get chOff() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get chOff' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charoff");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set chOff(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set chOff' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'chOff' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charoff", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get noWrap() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get noWrap' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "nowrap");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set noWrap(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set noWrap' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'noWrap' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "nowrap", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "nowrap");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vAlign() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vAlign' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "valign");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vAlign(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vAlign' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'vAlign' property on 'HTMLTableCellElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "valign", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get bgColor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bgColor' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "bgcolor");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set bgColor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set bgColor' called on an object that is not a valid instance of HTMLTableCellElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'bgColor' property on 'HTMLTableCellElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "bgcolor", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTableCellElement.prototype, {
+    colSpan: { enumerable: true },
+    rowSpan: { enumerable: true },
+    headers: { enumerable: true },
+    cellIndex: { enumerable: true },
+    scope: { enumerable: true },
+    abbr: { enumerable: true },
+    align: { enumerable: true },
+    axis: { enumerable: true },
+    height: { enumerable: true },
+    width: { enumerable: true },
+    ch: { enumerable: true },
+    chOff: { enumerable: true },
+    noWrap: { enumerable: true },
+    vAlign: { enumerable: true },
+    bgColor: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTableCellElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTableCellElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTableCellElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTableCellElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableColElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableColElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableColElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,339 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseNonNegativeInteger_helpers_strings = require("../helpers/strings.js").parseNonNegativeInteger;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTableColElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTableColElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTableColElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTableColElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTableColElement before HTMLElement");
+  }
+  class HTMLTableColElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get span() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get span' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "span");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set span(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set span' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'span' property on 'HTMLTableColElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "span", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLTableColElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get ch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ch' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "char");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set ch(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ch' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'ch' property on 'HTMLTableColElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "char", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get chOff() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get chOff' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charoff");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set chOff(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set chOff' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'chOff' property on 'HTMLTableColElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charoff", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vAlign() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vAlign' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "valign");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vAlign(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vAlign' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'vAlign' property on 'HTMLTableColElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "valign", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLTableColElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLTableColElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTableColElement.prototype, {
+    span: { enumerable: true },
+    align: { enumerable: true },
+    ch: { enumerable: true },
+    chOff: { enumerable: true },
+    vAlign: { enumerable: true },
+    width: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTableColElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTableColElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTableColElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTableColElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,725 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const HTMLTableCaptionElement = require("./HTMLTableCaptionElement.js");
+const HTMLTableSectionElement = require("./HTMLTableSectionElement.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTableElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTableElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTableElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTableElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTableElement before HTMLElement");
+  }
+  class HTMLTableElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    createCaption() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createCaption' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createCaption());
+    }
+
+    deleteCaption() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteCaption' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteCaption();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    createTHead() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createTHead' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createTHead());
+    }
+
+    deleteTHead() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteTHead' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteTHead();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    createTFoot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createTFoot' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createTFoot());
+    }
+
+    deleteTFoot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteTFoot' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteTFoot();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    createTBody() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createTBody' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createTBody());
+    }
+
+    insertRow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertRow' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'insertRow' on 'HTMLTableElement': parameter 1"
+          });
+        } else {
+          curArg = -1;
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].insertRow(...args));
+    }
+
+    deleteRow(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteRow' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'deleteRow' on 'HTMLTableElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["long"](curArg, {
+          context: "Failed to execute 'deleteRow' on 'HTMLTableElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteRow(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get caption() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get caption' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["caption"]);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set caption(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set caption' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = HTMLTableCaptionElement.convert(V, {
+          context: "Failed to set the 'caption' property on 'HTMLTableElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["caption"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get tHead() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tHead' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["tHead"]);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set tHead(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set tHead' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = HTMLTableSectionElement.convert(V, {
+          context: "Failed to set the 'tHead' property on 'HTMLTableElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["tHead"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get tFoot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tFoot' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["tFoot"]);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set tFoot(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set tFoot' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = HTMLTableSectionElement.convert(V, {
+          context: "Failed to set the 'tFoot' property on 'HTMLTableElement': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["tFoot"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get tBodies() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tBodies' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      return utils.getSameObject(this, "tBodies", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["tBodies"]);
+      });
+    }
+
+    get rows() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rows' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      return utils.getSameObject(this, "rows", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["rows"]);
+      });
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLTableElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get border() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get border' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "border");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set border(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set border' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'border' property on 'HTMLTableElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "border", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get frame() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get frame' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "frame");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set frame(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set frame' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'frame' property on 'HTMLTableElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "frame", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rules() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rules' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "rules");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rules(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rules' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'rules' property on 'HTMLTableElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "rules", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get summary() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get summary' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "summary");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set summary(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set summary' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'summary' property on 'HTMLTableElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "summary", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "width");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'width' property on 'HTMLTableElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "width", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get bgColor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bgColor' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "bgcolor");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set bgColor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set bgColor' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'bgColor' property on 'HTMLTableElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "bgcolor", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get cellPadding() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cellPadding' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "cellpadding");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set cellPadding(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cellPadding' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'cellPadding' property on 'HTMLTableElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "cellpadding", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get cellSpacing() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cellSpacing' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "cellspacing");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set cellSpacing(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cellSpacing' called on an object that is not a valid instance of HTMLTableElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'cellSpacing' property on 'HTMLTableElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "cellspacing", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTableElement.prototype, {
+    createCaption: { enumerable: true },
+    deleteCaption: { enumerable: true },
+    createTHead: { enumerable: true },
+    deleteTHead: { enumerable: true },
+    createTFoot: { enumerable: true },
+    deleteTFoot: { enumerable: true },
+    createTBody: { enumerable: true },
+    insertRow: { enumerable: true },
+    deleteRow: { enumerable: true },
+    caption: { enumerable: true },
+    tHead: { enumerable: true },
+    tFoot: { enumerable: true },
+    tBodies: { enumerable: true },
+    rows: { enumerable: true },
+    align: { enumerable: true },
+    border: { enumerable: true },
+    frame: { enumerable: true },
+    rules: { enumerable: true },
+    summary: { enumerable: true },
+    width: { enumerable: true },
+    bgColor: { enumerable: true },
+    cellPadding: { enumerable: true },
+    cellSpacing: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTableElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTableElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTableElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTableElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableRowElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableRowElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableRowElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,386 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTableRowElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTableRowElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTableRowElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTableRowElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTableRowElement before HTMLElement");
+  }
+  class HTMLTableRowElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    insertCell() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertCell' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'insertCell' on 'HTMLTableRowElement': parameter 1"
+          });
+        } else {
+          curArg = -1;
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].insertCell(...args));
+    }
+
+    deleteCell(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteCell' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'deleteCell' on 'HTMLTableRowElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["long"](curArg, {
+          context: "Failed to execute 'deleteCell' on 'HTMLTableRowElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteCell(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rowIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rowIndex' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      return esValue[implSymbol]["rowIndex"];
+    }
+
+    get sectionRowIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get sectionRowIndex' called on an object that is not a valid instance of HTMLTableRowElement."
+        );
+      }
+
+      return esValue[implSymbol]["sectionRowIndex"];
+    }
+
+    get cells() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cells' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      return utils.getSameObject(this, "cells", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["cells"]);
+      });
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLTableRowElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get ch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ch' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "char");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set ch(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ch' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'ch' property on 'HTMLTableRowElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "char", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get chOff() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get chOff' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charoff");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set chOff(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set chOff' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'chOff' property on 'HTMLTableRowElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charoff", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vAlign() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vAlign' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "valign");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vAlign(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set vAlign' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'vAlign' property on 'HTMLTableRowElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "valign", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get bgColor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bgColor' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "bgcolor");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set bgColor(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set bgColor' called on an object that is not a valid instance of HTMLTableRowElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'bgColor' property on 'HTMLTableRowElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "bgcolor", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTableRowElement.prototype, {
+    insertCell: { enumerable: true },
+    deleteCell: { enumerable: true },
+    rowIndex: { enumerable: true },
+    sectionRowIndex: { enumerable: true },
+    cells: { enumerable: true },
+    align: { enumerable: true },
+    ch: { enumerable: true },
+    chOff: { enumerable: true },
+    vAlign: { enumerable: true },
+    bgColor: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTableRowElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTableRowElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTableRowElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTableRowElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableSectionElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableSectionElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTableSectionElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,329 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTableSectionElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTableSectionElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTableSectionElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTableSectionElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTableSectionElement before HTMLElement");
+  }
+  class HTMLTableSectionElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    insertRow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertRow' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'insertRow' on 'HTMLTableSectionElement': parameter 1"
+          });
+        } else {
+          curArg = -1;
+        }
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].insertRow(...args));
+    }
+
+    deleteRow(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteRow' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'deleteRow' on 'HTMLTableSectionElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["long"](curArg, {
+          context: "Failed to execute 'deleteRow' on 'HTMLTableSectionElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteRow(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rows() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rows' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      return utils.getSameObject(this, "rows", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["rows"]);
+      });
+    }
+
+    get align() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get align' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "align");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set align(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set align' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'align' property on 'HTMLTableSectionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "align", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get ch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ch' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "char");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set ch(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ch' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'ch' property on 'HTMLTableSectionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "char", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get chOff() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get chOff' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "charoff");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set chOff(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set chOff' called on an object that is not a valid instance of HTMLTableSectionElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'chOff' property on 'HTMLTableSectionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "charoff", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get vAlign() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get vAlign' called on an object that is not a valid instance of HTMLTableSectionElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "valign");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set vAlign(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set vAlign' called on an object that is not a valid instance of HTMLTableSectionElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'vAlign' property on 'HTMLTableSectionElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "valign", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTableSectionElement.prototype, {
+    insertRow: { enumerable: true },
+    deleteRow: { enumerable: true },
+    rows: { enumerable: true },
+    align: { enumerable: true },
+    ch: { enumerable: true },
+    chOff: { enumerable: true },
+    vAlign: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTableSectionElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTableSectionElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTableSectionElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTableSectionElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTemplateElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTemplateElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTemplateElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,126 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTemplateElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTemplateElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTemplateElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTemplateElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTemplateElement before HTMLElement");
+  }
+  class HTMLTemplateElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get content() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get content' called on an object that is not a valid instance of HTMLTemplateElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["content"]);
+    }
+  }
+  Object.defineProperties(HTMLTemplateElement.prototype, {
+    content: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTemplateElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTemplateElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTemplateElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTemplateElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTextAreaElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTextAreaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTextAreaElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1088 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const SelectionMode = require("./SelectionMode.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseInteger_helpers_strings = require("../helpers/strings.js").parseInteger;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTextAreaElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTextAreaElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTextAreaElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTextAreaElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTextAreaElement before HTMLElement");
+  }
+  class HTMLTextAreaElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    checkValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'checkValidity' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      return esValue[implSymbol].checkValidity();
+    }
+
+    reportValidity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'reportValidity' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol].reportValidity();
+    }
+
+    setCustomValidity(error) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setCustomValidity' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setCustomValidity' on 'HTMLTextAreaElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'setCustomValidity' on 'HTMLTextAreaElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setCustomValidity(...args);
+    }
+
+    select() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'select' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      return esValue[implSymbol].select();
+    }
+
+    setRangeText(replacement) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setRangeText' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      switch (arguments.length) {
+        case 1:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 1"
+            });
+            args.push(curArg);
+          }
+          break;
+        case 2:
+          throw new TypeError(
+            "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': only " +
+              arguments.length +
+              " arguments present."
+          );
+          break;
+        case 3:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 3"
+            });
+            args.push(curArg);
+          }
+          break;
+        default:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["unsigned long"](curArg, {
+              context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 3"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[3];
+            if (curArg !== undefined) {
+              curArg = SelectionMode.convert(curArg, {
+                context: "Failed to execute 'setRangeText' on 'HTMLTextAreaElement': parameter 4"
+              });
+            } else {
+              curArg = "preserve";
+            }
+            args.push(curArg);
+          }
+      }
+      return esValue[implSymbol].setRangeText(...args);
+    }
+
+    setSelectionRange(start, end) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'setSelectionRange' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setSelectionRange' on 'HTMLTextAreaElement': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setSelectionRange' on 'HTMLTextAreaElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setSelectionRange' on 'HTMLTextAreaElement': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'setSelectionRange' on 'HTMLTextAreaElement': parameter 3"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setSelectionRange(...args);
+    }
+
+    get autocomplete() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get autocomplete' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "autocomplete");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autocomplete(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set autocomplete' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'autocomplete' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "autocomplete", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get autofocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get autofocus' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "autofocus");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set autofocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set autofocus' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'autofocus' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "autofocus", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "autofocus");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get cols() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cols' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["cols"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set cols(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set cols' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'cols' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["cols"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get dirName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dirName' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "dirname");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set dirName(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set dirName' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'dirName' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "dirname", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get disabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get disabled' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "disabled");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set disabled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set disabled' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'disabled' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "disabled", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "disabled");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get form() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get form' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["form"]);
+    }
+
+    get inputMode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get inputMode' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "inputmode");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set inputMode(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set inputMode' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'inputMode' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "inputmode", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get maxLength() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get maxLength' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "maxlength");
+        if (value === null) {
+          return 0;
+        }
+        value = parseInteger_helpers_strings(value);
+        return value !== null && conversions.long(value) === value ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set maxLength(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set maxLength' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'maxLength' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "maxlength", String(V));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get minLength() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get minLength' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "minlength");
+        if (value === null) {
+          return 0;
+        }
+        value = parseInteger_helpers_strings(value);
+        return value !== null && conversions.long(value) === value ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set minLength(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set minLength' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'minLength' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "minlength", String(V));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "name");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set name(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set name' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'name' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "name", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get placeholder() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get placeholder' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "placeholder");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set placeholder(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set placeholder' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'placeholder' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "placeholder", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get readOnly() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readOnly' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "readonly");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set readOnly(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set readOnly' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'readOnly' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "readonly", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "readonly");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get required() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get required' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "required");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set required(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set required' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'required' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "required", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "required");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get rows() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rows' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["rows"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set rows(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set rows' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'rows' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["rows"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get wrap() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get wrap' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "wrap");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set wrap(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set wrap' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'wrap' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "wrap", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+
+    get defaultValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get defaultValue' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["defaultValue"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set defaultValue(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set defaultValue' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'defaultValue' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["defaultValue"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["value"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'value' property on 'HTMLTextAreaElement': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["value"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get textLength() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get textLength' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol]["textLength"];
+    }
+
+    get willValidate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get willValidate' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol]["willValidate"];
+    }
+
+    get validity() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get validity' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["validity"]);
+    }
+
+    get validationMessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get validationMessage' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol]["validationMessage"];
+    }
+
+    get labels() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get labels' called on an object that is not a valid instance of HTMLTextAreaElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["labels"]);
+    }
+
+    get selectionStart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectionStart' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol]["selectionStart"];
+    }
+
+    set selectionStart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectionStart' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'selectionStart' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      esValue[implSymbol]["selectionStart"] = V;
+    }
+
+    get selectionEnd() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectionEnd' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol]["selectionEnd"];
+    }
+
+    set selectionEnd(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectionEnd' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'selectionEnd' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      esValue[implSymbol]["selectionEnd"] = V;
+    }
+
+    get selectionDirection() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get selectionDirection' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      return esValue[implSymbol]["selectionDirection"];
+    }
+
+    set selectionDirection(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set selectionDirection' called on an object that is not a valid instance of HTMLTextAreaElement."
+        );
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'selectionDirection' property on 'HTMLTextAreaElement': The provided value"
+      });
+
+      esValue[implSymbol]["selectionDirection"] = V;
+    }
+  }
+  Object.defineProperties(HTMLTextAreaElement.prototype, {
+    checkValidity: { enumerable: true },
+    reportValidity: { enumerable: true },
+    setCustomValidity: { enumerable: true },
+    select: { enumerable: true },
+    setRangeText: { enumerable: true },
+    setSelectionRange: { enumerable: true },
+    autocomplete: { enumerable: true },
+    autofocus: { enumerable: true },
+    cols: { enumerable: true },
+    dirName: { enumerable: true },
+    disabled: { enumerable: true },
+    form: { enumerable: true },
+    inputMode: { enumerable: true },
+    maxLength: { enumerable: true },
+    minLength: { enumerable: true },
+    name: { enumerable: true },
+    placeholder: { enumerable: true },
+    readOnly: { enumerable: true },
+    required: { enumerable: true },
+    rows: { enumerable: true },
+    wrap: { enumerable: true },
+    type: { enumerable: true },
+    defaultValue: { enumerable: true },
+    value: { enumerable: true },
+    textLength: { enumerable: true },
+    willValidate: { enumerable: true },
+    validity: { enumerable: true },
+    validationMessage: { enumerable: true },
+    labels: { enumerable: true },
+    selectionStart: { enumerable: true },
+    selectionEnd: { enumerable: true },
+    selectionDirection: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTextAreaElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTextAreaElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTextAreaElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTextAreaElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTimeElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTimeElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTimeElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTimeElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTimeElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTimeElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTimeElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTimeElement before HTMLElement");
+  }
+  class HTMLTimeElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get dateTime() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dateTime' called on an object that is not a valid instance of HTMLTimeElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "datetime");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set dateTime(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set dateTime' called on an object that is not a valid instance of HTMLTimeElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'dateTime' property on 'HTMLTimeElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "datetime", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTimeElement.prototype, {
+    dateTime: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTimeElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTimeElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTimeElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTimeElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTitleElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTitleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTitleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,152 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTitleElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTitleElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTitleElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTitleElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTitleElement before HTMLElement");
+  }
+  class HTMLTitleElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get text() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get text' called on an object that is not a valid instance of HTMLTitleElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["text"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set text(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set text' called on an object that is not a valid instance of HTMLTitleElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'text' property on 'HTMLTitleElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["text"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLTitleElement.prototype, {
+    text: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTitleElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTitleElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTitleElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTitleElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTrackElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTrackElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLTrackElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,334 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLTrackElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLTrackElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLTrackElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLTrackElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLTrackElement before HTMLElement");
+  }
+  class HTMLTrackElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get kind() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get kind' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "kind");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set kind(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set kind' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'kind' property on 'HTMLTrackElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "kind", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get src() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get src' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "src");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set src(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set src' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'src' property on 'HTMLTrackElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "src", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get srclang() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get srclang' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "srclang");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set srclang(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set srclang' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'srclang' property on 'HTMLTrackElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "srclang", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get label() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get label' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "label");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set label(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set label' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'label' property on 'HTMLTrackElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "label", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get default() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get default' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "default");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set default(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set default' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'default' property on 'HTMLTrackElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "default", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "default");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get readyState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readyState' called on an object that is not a valid instance of HTMLTrackElement.");
+      }
+
+      return esValue[implSymbol]["readyState"];
+    }
+  }
+  Object.defineProperties(HTMLTrackElement.prototype, {
+    kind: { enumerable: true },
+    src: { enumerable: true },
+    srclang: { enumerable: true },
+    label: { enumerable: true },
+    default: { enumerable: true },
+    readyState: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLTrackElement", configurable: true },
+    NONE: { value: 0, enumerable: true },
+    LOADING: { value: 1, enumerable: true },
+    LOADED: { value: 2, enumerable: true },
+    ERROR: { value: 3, enumerable: true }
+  });
+  Object.defineProperties(HTMLTrackElement, {
+    NONE: { value: 0, enumerable: true },
+    LOADING: { value: 1, enumerable: true },
+    LOADED: { value: 2, enumerable: true },
+    ERROR: { value: 3, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLTrackElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLTrackElement
+  });
+};
+
+const Impl = require("../nodes/HTMLTrackElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLUListElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLUListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLUListElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,192 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLUListElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLUListElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLUListElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLUListElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLUListElement before HTMLElement");
+  }
+  class HTMLUListElement extends globalObject.HTMLElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get compact() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get compact' called on an object that is not a valid instance of HTMLUListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "compact");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set compact(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set compact' called on an object that is not a valid instance of HTMLUListElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'compact' property on 'HTMLUListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "compact", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "compact");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of HTMLUListElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "type");
+        return value === null ? "" : value;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set type(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set type' called on an object that is not a valid instance of HTMLUListElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'type' property on 'HTMLUListElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "type", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLUListElement.prototype, {
+    compact: { enumerable: true },
+    type: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLUListElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLUListElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLUListElement
+  });
+};
+
+const Impl = require("../nodes/HTMLUListElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLUnknownElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLUnknownElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLUnknownElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLElement = require("./HTMLElement.js");
+
+const interfaceName = "HTMLUnknownElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLUnknownElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLUnknownElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLUnknownElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLUnknownElement before HTMLElement");
+  }
+  class HTMLUnknownElement extends globalObject.HTMLElement {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(HTMLUnknownElement.prototype, {
+    [Symbol.toStringTag]: { value: "HTMLUnknownElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLUnknownElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLUnknownElement
+  });
+};
+
+const Impl = require("../nodes/HTMLUnknownElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLVideoElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLVideoElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HTMLVideoElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,310 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HTMLConstructor_helpers_html_constructor = require("../helpers/html-constructor.js").HTMLConstructor;
+const parseNonNegativeInteger_helpers_strings = require("../helpers/strings.js").parseNonNegativeInteger;
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const parseURLToResultingURLRecord_helpers_document_base_url =
+  require("../helpers/document-base-url.js").parseURLToResultingURLRecord;
+const serializeURLwhatwg_url = require("whatwg-url").serializeURL;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const HTMLMediaElement = require("./HTMLMediaElement.js");
+
+const interfaceName = "HTMLVideoElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HTMLVideoElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HTMLVideoElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HTMLVideoElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  HTMLMediaElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.HTMLMediaElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate HTMLVideoElement before HTMLMediaElement");
+  }
+  class HTMLVideoElement extends globalObject.HTMLMediaElement {
+    constructor() {
+      return HTMLConstructor_helpers_html_constructor(globalObject, interfaceName, new.target);
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "width");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set width(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set width' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'width' property on 'HTMLVideoElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "width", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        let value = esValue[implSymbol].getAttributeNS(null, "height");
+        if (value === null) {
+          return 0;
+        }
+        value = parseNonNegativeInteger_helpers_strings(value);
+        return value !== null && value >= 0 && value <= 2147483647 ? value : 0;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set height(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set height' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'height' property on 'HTMLVideoElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const n = V <= 2147483647 ? V : 0;
+        esValue[implSymbol].setAttributeNS(null, "height", String(n));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get videoWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get videoWidth' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      return esValue[implSymbol]["videoWidth"];
+    }
+
+    get videoHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get videoHeight' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      return esValue[implSymbol]["videoHeight"];
+    }
+
+    get poster() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get poster' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        const value = esValue[implSymbol].getAttributeNS(null, "poster");
+        if (value === null) {
+          return "";
+        }
+        const urlRecord = parseURLToResultingURLRecord_helpers_document_base_url(
+          value,
+          esValue[implSymbol]._ownerDocument
+        );
+        if (urlRecord !== null) {
+          return serializeURLwhatwg_url(urlRecord);
+        }
+        return conversions.USVString(value);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set poster(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set poster' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      V = conversions["USVString"](V, {
+        context: "Failed to set the 'poster' property on 'HTMLVideoElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol].setAttributeNS(null, "poster", V);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get playsInline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get playsInline' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].hasAttributeNS(null, "playsinline");
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set playsInline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set playsInline' called on an object that is not a valid instance of HTMLVideoElement.");
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'playsInline' property on 'HTMLVideoElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        if (V) {
+          esValue[implSymbol].setAttributeNS(null, "playsinline", "");
+        } else {
+          esValue[implSymbol].removeAttributeNS(null, "playsinline");
+        }
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(HTMLVideoElement.prototype, {
+    width: { enumerable: true },
+    height: { enumerable: true },
+    videoWidth: { enumerable: true },
+    videoHeight: { enumerable: true },
+    poster: { enumerable: true },
+    playsInline: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HTMLVideoElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HTMLVideoElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HTMLVideoElement
+  });
+};
+
+const Impl = require("../nodes/HTMLVideoElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HashChangeEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HashChangeEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HashChangeEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,153 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const HashChangeEventInit = require("./HashChangeEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "HashChangeEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'HashChangeEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["HashChangeEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor HashChangeEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate HashChangeEvent before Event");
+  }
+  class HashChangeEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'HashChangeEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'HashChangeEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = HashChangeEventInit.convert(curArg, { context: "Failed to construct 'HashChangeEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get oldURL() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oldURL' called on an object that is not a valid instance of HashChangeEvent.");
+      }
+
+      return esValue[implSymbol]["oldURL"];
+    }
+
+    get newURL() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get newURL' called on an object that is not a valid instance of HashChangeEvent.");
+      }
+
+      return esValue[implSymbol]["newURL"];
+    }
+  }
+  Object.defineProperties(HashChangeEvent.prototype, {
+    oldURL: { enumerable: true },
+    newURL: { enumerable: true },
+    [Symbol.toStringTag]: { value: "HashChangeEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = HashChangeEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: HashChangeEvent
+  });
+};
+
+const Impl = require("../events/HashChangeEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/HashChangeEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/HashChangeEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/HashChangeEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "newURL";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["USVString"](value, { context: context + " has member 'newURL' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "oldURL";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["USVString"](value, { context: context + " has member 'oldURL' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Headers.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Headers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Headers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,379 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Function = require("./Function.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Headers";
+
+const IteratorPrototype = Object.create(utils.IteratorPrototype, {
+  next: {
+    value: function next() {
+      const internal = this && this[utils.iterInternalSymbol];
+      if (!internal) {
+        throw new TypeError("next() called on a value that is not an iterator prototype object");
+      }
+
+      const { target, kind, index } = internal;
+      const values = Array.from(target[implSymbol]);
+      const len = values.length;
+      if (index >= len) {
+        return { value: undefined, done: true };
+      }
+
+      const pair = values[index];
+      internal.index = index + 1;
+      return utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind);
+    },
+    writable: true,
+    enumerable: true,
+    configurable: true
+  },
+  [Symbol.toStringTag]: {
+    value: "Headers Iterator",
+    configurable: true
+  }
+});
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Headers'.`);
+};
+
+exports.createDefaultIterator = (target, kind) => {
+  const iterator = Object.create(IteratorPrototype);
+  Object.defineProperty(iterator, utils.iterInternalSymbol, {
+    value: { target, kind, index: 0 },
+    configurable: true
+  });
+  return iterator;
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Headers"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Headers is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Headers {
+    constructor() {
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          if (utils.isObject(curArg)) {
+            if (curArg[Symbol.iterator] !== undefined) {
+              if (!utils.isObject(curArg)) {
+                throw new TypeError(
+                  "Failed to construct 'Headers': parameter 1" + " sequence" + " is not an iterable object."
+                );
+              } else {
+                const V = [];
+                const tmp = curArg;
+                for (let nextItem of tmp) {
+                  if (!utils.isObject(nextItem)) {
+                    throw new TypeError(
+                      "Failed to construct 'Headers': parameter 1" +
+                        " sequence" +
+                        "'s element" +
+                        " is not an iterable object."
+                    );
+                  } else {
+                    const V = [];
+                    const tmp = nextItem;
+                    for (let nextItem of tmp) {
+                      nextItem = conversions["ByteString"](nextItem, {
+                        context:
+                          "Failed to construct 'Headers': parameter 1" + " sequence" + "'s element" + "'s element"
+                      });
+
+                      V.push(nextItem);
+                    }
+                    nextItem = V;
+                  }
+
+                  V.push(nextItem);
+                }
+                curArg = V;
+              }
+            } else {
+              if (!utils.isObject(curArg)) {
+                throw new TypeError("Failed to construct 'Headers': parameter 1" + " record" + " is not an object.");
+              } else {
+                const result = Object.create(null);
+                for (const key of Reflect.ownKeys(curArg)) {
+                  const desc = Object.getOwnPropertyDescriptor(curArg, key);
+                  if (desc && desc.enumerable) {
+                    let typedKey = key;
+
+                    typedKey = conversions["ByteString"](typedKey, {
+                      context: "Failed to construct 'Headers': parameter 1" + " record" + "'s key"
+                    });
+
+                    let typedValue = curArg[key];
+
+                    typedValue = conversions["ByteString"](typedValue, {
+                      context: "Failed to construct 'Headers': parameter 1" + " record" + "'s value"
+                    });
+
+                    result[typedKey] = typedValue;
+                  }
+                }
+                curArg = result;
+              }
+            }
+          } else {
+            throw new TypeError("Failed to construct 'Headers': parameter 1" + " is not of any supported type.");
+          }
+        }
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    append(name, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'append' called on an object that is not a valid instance of Headers.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'append' on 'Headers': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'append' on 'Headers': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'append' on 'Headers': parameter 2" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].append(...args);
+    }
+
+    delete(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'delete' called on an object that is not a valid instance of Headers.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'delete' on 'Headers': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'delete' on 'Headers': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].delete(...args);
+    }
+
+    get(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get' called on an object that is not a valid instance of Headers.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'get' on 'Headers': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'get' on 'Headers': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].get(...args);
+    }
+
+    has(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'has' called on an object that is not a valid instance of Headers.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'has' on 'Headers': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'has' on 'Headers': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].has(...args);
+    }
+
+    set(name, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set' called on an object that is not a valid instance of Headers.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'set' on 'Headers': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'set' on 'Headers': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["ByteString"](curArg, { context: "Failed to execute 'set' on 'Headers': parameter 2" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].set(...args);
+    }
+
+    keys() {
+      if (!exports.is(this)) {
+        throw new TypeError("'keys' called on an object that is not a valid instance of Headers.");
+      }
+      return exports.createDefaultIterator(this, "key");
+    }
+
+    values() {
+      if (!exports.is(this)) {
+        throw new TypeError("'values' called on an object that is not a valid instance of Headers.");
+      }
+      return exports.createDefaultIterator(this, "value");
+    }
+
+    entries() {
+      if (!exports.is(this)) {
+        throw new TypeError("'entries' called on an object that is not a valid instance of Headers.");
+      }
+      return exports.createDefaultIterator(this, "key+value");
+    }
+
+    forEach(callback) {
+      if (!exports.is(this)) {
+        throw new TypeError("'forEach' called on an object that is not a valid instance of Headers.");
+      }
+      if (arguments.length < 1) {
+        throw new TypeError("Failed to execute 'forEach' on 'iterable': 1 argument required, " + "but only 0 present.");
+      }
+      callback = Function.convert(callback, {
+        context: "Failed to execute 'forEach' on 'iterable': The callback provided as parameter 1"
+      });
+      const thisArg = arguments[1];
+      let pairs = Array.from(this[implSymbol]);
+      let i = 0;
+      while (i < pairs.length) {
+        const [key, value] = pairs[i].map(utils.tryWrapperForImpl);
+        callback.call(thisArg, value, key, this);
+        pairs = Array.from(this[implSymbol]);
+        i++;
+      }
+    }
+  }
+  Object.defineProperties(Headers.prototype, {
+    append: { enumerable: true },
+    delete: { enumerable: true },
+    get: { enumerable: true },
+    has: { enumerable: true },
+    set: { enumerable: true },
+    keys: { enumerable: true },
+    values: { enumerable: true },
+    entries: { enumerable: true },
+    forEach: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Headers", configurable: true },
+    [Symbol.iterator]: { value: Headers.prototype.entries, configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Headers;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Headers
+  });
+};
+
+const Impl = require("../fetch/Headers-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/History.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/History.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/History.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,256 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "History";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'History'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["History"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor History is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class History {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    go() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'go' called on an object that is not a valid instance of History.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, { context: "Failed to execute 'go' on 'History': parameter 1" });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].go(...args);
+    }
+
+    back() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'back' called on an object that is not a valid instance of History.");
+      }
+
+      return esValue[implSymbol].back();
+    }
+
+    forward() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'forward' called on an object that is not a valid instance of History.");
+      }
+
+      return esValue[implSymbol].forward();
+    }
+
+    pushState(data, title) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'pushState' called on an object that is not a valid instance of History.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'pushState' on 'History': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["any"](curArg, { context: "Failed to execute 'pushState' on 'History': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'pushState' on 'History': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'pushState' on 'History': parameter 3"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].pushState(...args);
+    }
+
+    replaceState(data, title) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceState' called on an object that is not a valid instance of History.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'replaceState' on 'History': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["any"](curArg, { context: "Failed to execute 'replaceState' on 'History': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'replaceState' on 'History': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'replaceState' on 'History': parameter 3"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].replaceState(...args);
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of History.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+
+    get state() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get state' called on an object that is not a valid instance of History.");
+      }
+
+      return esValue[implSymbol]["state"];
+    }
+  }
+  Object.defineProperties(History.prototype, {
+    go: { enumerable: true },
+    back: { enumerable: true },
+    forward: { enumerable: true },
+    pushState: { enumerable: true },
+    replaceState: { enumerable: true },
+    length: { enumerable: true },
+    state: { enumerable: true },
+    [Symbol.toStringTag]: { value: "History", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = History;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: History
+  });
+};
+
+const Impl = require("../window/History-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/InputEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/InputEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/InputEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,164 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const InputEventInit = require("./InputEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const UIEvent = require("./UIEvent.js");
+
+const interfaceName = "InputEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'InputEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["InputEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor InputEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  UIEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.UIEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate InputEvent before UIEvent");
+  }
+  class InputEvent extends globalObject.UIEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'InputEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'InputEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = InputEventInit.convert(curArg, { context: "Failed to construct 'InputEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get data() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get data' called on an object that is not a valid instance of InputEvent.");
+      }
+
+      return esValue[implSymbol]["data"];
+    }
+
+    get isComposing() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get isComposing' called on an object that is not a valid instance of InputEvent.");
+      }
+
+      return esValue[implSymbol]["isComposing"];
+    }
+
+    get inputType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get inputType' called on an object that is not a valid instance of InputEvent.");
+      }
+
+      return esValue[implSymbol]["inputType"];
+    }
+  }
+  Object.defineProperties(InputEvent.prototype, {
+    data: { enumerable: true },
+    isComposing: { enumerable: true },
+    inputType: { enumerable: true },
+    [Symbol.toStringTag]: { value: "InputEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = InputEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: InputEvent
+  });
+};
+
+const Impl = require("../events/InputEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/InputEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/InputEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/InputEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const UIEventInit = require("./UIEventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  UIEventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "data";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = conversions["DOMString"](value, { context: context + " has member 'data' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "inputType";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'inputType' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "isComposing";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'isComposing' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/KeyboardEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/KeyboardEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/KeyboardEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,413 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const KeyboardEventInit = require("./KeyboardEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const UIEvent = require("./UIEvent.js");
+
+const interfaceName = "KeyboardEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'KeyboardEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["KeyboardEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor KeyboardEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  UIEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.UIEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate KeyboardEvent before UIEvent");
+  }
+  class KeyboardEvent extends globalObject.UIEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'KeyboardEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'KeyboardEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = KeyboardEventInit.convert(curArg, { context: "Failed to construct 'KeyboardEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    getModifierState(keyArg) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getModifierState' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getModifierState' on 'KeyboardEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getModifierState' on 'KeyboardEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getModifierState(...args);
+    }
+
+    initKeyboardEvent(typeArg) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initKeyboardEvent' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = utils.tryImplForWrapper(curArg);
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[4];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 5"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[5];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned long"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 6"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[6];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 7"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[7];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 8"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[8];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 9"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[9];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initKeyboardEvent' on 'KeyboardEvent': parameter 10"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initKeyboardEvent(...args);
+    }
+
+    get key() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get key' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["key"];
+    }
+
+    get code() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get code' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["code"];
+    }
+
+    get location() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get location' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["location"];
+    }
+
+    get ctrlKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ctrlKey' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["ctrlKey"];
+    }
+
+    get shiftKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get shiftKey' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["shiftKey"];
+    }
+
+    get altKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get altKey' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["altKey"];
+    }
+
+    get metaKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get metaKey' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["metaKey"];
+    }
+
+    get repeat() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get repeat' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["repeat"];
+    }
+
+    get isComposing() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get isComposing' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["isComposing"];
+    }
+
+    get charCode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get charCode' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["charCode"];
+    }
+
+    get keyCode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get keyCode' called on an object that is not a valid instance of KeyboardEvent.");
+      }
+
+      return esValue[implSymbol]["keyCode"];
+    }
+  }
+  Object.defineProperties(KeyboardEvent.prototype, {
+    getModifierState: { enumerable: true },
+    initKeyboardEvent: { enumerable: true },
+    key: { enumerable: true },
+    code: { enumerable: true },
+    location: { enumerable: true },
+    ctrlKey: { enumerable: true },
+    shiftKey: { enumerable: true },
+    altKey: { enumerable: true },
+    metaKey: { enumerable: true },
+    repeat: { enumerable: true },
+    isComposing: { enumerable: true },
+    charCode: { enumerable: true },
+    keyCode: { enumerable: true },
+    [Symbol.toStringTag]: { value: "KeyboardEvent", configurable: true },
+    DOM_KEY_LOCATION_STANDARD: { value: 0x00, enumerable: true },
+    DOM_KEY_LOCATION_LEFT: { value: 0x01, enumerable: true },
+    DOM_KEY_LOCATION_RIGHT: { value: 0x02, enumerable: true },
+    DOM_KEY_LOCATION_NUMPAD: { value: 0x03, enumerable: true }
+  });
+  Object.defineProperties(KeyboardEvent, {
+    DOM_KEY_LOCATION_STANDARD: { value: 0x00, enumerable: true },
+    DOM_KEY_LOCATION_LEFT: { value: 0x01, enumerable: true },
+    DOM_KEY_LOCATION_RIGHT: { value: 0x02, enumerable: true },
+    DOM_KEY_LOCATION_NUMPAD: { value: 0x03, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = KeyboardEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: KeyboardEvent
+  });
+};
+
+const Impl = require("../events/KeyboardEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/KeyboardEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/KeyboardEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/KeyboardEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,104 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventModifierInit = require("./EventModifierInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventModifierInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "charCode";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'charCode' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "code";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'code' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "isComposing";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'isComposing' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "key";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'key' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "keyCode";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'keyCode' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "location";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'location' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "repeat";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'repeat' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Location.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Location.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Location.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,370 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Location";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Location'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Location"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Location is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Object.defineProperties(
+    wrapper,
+    Object.getOwnPropertyDescriptors({
+      assign(url) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+        if (!exports.is(esValue)) {
+          throw new TypeError("'assign' called on an object that is not a valid instance of Location.");
+        }
+
+        if (arguments.length < 1) {
+          throw new TypeError(
+            "Failed to execute 'assign' on 'Location': 1 argument required, but only " + arguments.length + " present."
+          );
+        }
+        const args = [];
+        {
+          let curArg = arguments[0];
+          curArg = conversions["USVString"](curArg, {
+            context: "Failed to execute 'assign' on 'Location': parameter 1"
+          });
+          args.push(curArg);
+        }
+        return esValue[implSymbol].assign(...args);
+      },
+      replace(url) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+        if (!exports.is(esValue)) {
+          throw new TypeError("'replace' called on an object that is not a valid instance of Location.");
+        }
+
+        if (arguments.length < 1) {
+          throw new TypeError(
+            "Failed to execute 'replace' on 'Location': 1 argument required, but only " + arguments.length + " present."
+          );
+        }
+        const args = [];
+        {
+          let curArg = arguments[0];
+          curArg = conversions["USVString"](curArg, {
+            context: "Failed to execute 'replace' on 'Location': parameter 1"
+          });
+          args.push(curArg);
+        }
+        return esValue[implSymbol].replace(...args);
+      },
+      reload() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+        if (!exports.is(esValue)) {
+          throw new TypeError("'reload' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol].reload();
+      },
+      get href() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get href' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["href"];
+      },
+      set href(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set href' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'href' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["href"] = V;
+      },
+      toString() {
+        const esValue = this;
+        if (!exports.is(esValue)) {
+          throw new TypeError("'toString' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["href"];
+      },
+      get origin() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get origin' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["origin"];
+      },
+      get protocol() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get protocol' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["protocol"];
+      },
+      set protocol(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set protocol' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'protocol' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["protocol"] = V;
+      },
+      get host() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get host' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["host"];
+      },
+      set host(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set host' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'host' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["host"] = V;
+      },
+      get hostname() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get hostname' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["hostname"];
+      },
+      set hostname(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set hostname' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'hostname' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["hostname"] = V;
+      },
+      get port() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get port' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["port"];
+      },
+      set port(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set port' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'port' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["port"] = V;
+      },
+      get pathname() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get pathname' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["pathname"];
+      },
+      set pathname(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set pathname' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'pathname' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["pathname"] = V;
+      },
+      get search() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get search' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["search"];
+      },
+      set search(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set search' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'search' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["search"] = V;
+      },
+      get hash() {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'get hash' called on an object that is not a valid instance of Location.");
+        }
+
+        return esValue[implSymbol]["hash"];
+      },
+      set hash(V) {
+        const esValue = this !== null && this !== undefined ? this : globalObject;
+
+        if (!exports.is(esValue)) {
+          throw new TypeError("'set hash' called on an object that is not a valid instance of Location.");
+        }
+
+        V = conversions["USVString"](V, {
+          context: "Failed to set the 'hash' property on 'Location': The provided value"
+        });
+
+        esValue[implSymbol]["hash"] = V;
+      }
+    })
+  );
+
+  Object.defineProperties(wrapper, {
+    assign: { configurable: false, writable: false },
+    replace: { configurable: false, writable: false },
+    reload: { configurable: false, writable: false },
+    href: { configurable: false },
+    toString: { configurable: false, writable: false },
+    origin: { configurable: false },
+    protocol: { configurable: false },
+    host: { configurable: false },
+    hostname: { configurable: false },
+    port: { configurable: false },
+    pathname: { configurable: false },
+    search: { configurable: false },
+    hash: { configurable: false }
+  });
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Location {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(Location.prototype, { [Symbol.toStringTag]: { value: "Location", configurable: true } });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Location;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Location
+  });
+};
+
+const Impl = require("../window/Location-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MessageEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MessageEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MessageEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,301 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const MessageEventInit = require("./MessageEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "MessageEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'MessageEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["MessageEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor MessageEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker", "AudioWorklet"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate MessageEvent before Event");
+  }
+  class MessageEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'MessageEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'MessageEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = MessageEventInit.convert(curArg, { context: "Failed to construct 'MessageEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    initMessageEvent(type) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initMessageEvent' called on an object that is not a valid instance of MessageEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initMessageEvent' on 'MessageEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          curArg = conversions["any"](curArg, {
+            context: "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 4"
+          });
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[4];
+        if (curArg !== undefined) {
+          curArg = conversions["USVString"](curArg, {
+            context: "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 5"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[5];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 6"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[6];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = utils.tryImplForWrapper(curArg);
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[7];
+        if (curArg !== undefined) {
+          if (!utils.isObject(curArg)) {
+            throw new TypeError(
+              "Failed to execute 'initMessageEvent' on 'MessageEvent': parameter 8" + " is not an iterable object."
+            );
+          } else {
+            const V = [];
+            const tmp = curArg;
+            for (let nextItem of tmp) {
+              nextItem = utils.tryImplForWrapper(nextItem);
+
+              V.push(nextItem);
+            }
+            curArg = V;
+          }
+        } else {
+          curArg = [];
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initMessageEvent(...args);
+    }
+
+    get data() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get data' called on an object that is not a valid instance of MessageEvent.");
+      }
+
+      return esValue[implSymbol]["data"];
+    }
+
+    get origin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get origin' called on an object that is not a valid instance of MessageEvent.");
+      }
+
+      return esValue[implSymbol]["origin"];
+    }
+
+    get lastEventId() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lastEventId' called on an object that is not a valid instance of MessageEvent.");
+      }
+
+      return esValue[implSymbol]["lastEventId"];
+    }
+
+    get source() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get source' called on an object that is not a valid instance of MessageEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["source"]);
+    }
+
+    get ports() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ports' called on an object that is not a valid instance of MessageEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ports"]);
+    }
+  }
+  Object.defineProperties(MessageEvent.prototype, {
+    initMessageEvent: { enumerable: true },
+    data: { enumerable: true },
+    origin: { enumerable: true },
+    lastEventId: { enumerable: true },
+    source: { enumerable: true },
+    ports: { enumerable: true },
+    [Symbol.toStringTag]: { value: "MessageEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = MessageEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: MessageEvent
+  });
+};
+
+const Impl = require("../events/MessageEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MessageEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MessageEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MessageEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,94 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "data";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["any"](value, { context: context + " has member 'data' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "lastEventId";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["DOMString"](value, { context: context + " has member 'lastEventId' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "origin";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["USVString"](value, { context: context + " has member 'origin' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+
+  {
+    const key = "ports";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (!utils.isObject(value)) {
+        throw new TypeError(context + " has member 'ports' that" + " is not an iterable object.");
+      } else {
+        const V = [];
+        const tmp = value;
+        for (let nextItem of tmp) {
+          nextItem = utils.tryImplForWrapper(nextItem);
+
+          V.push(nextItem);
+        }
+        value = V;
+      }
+
+      ret[key] = value;
+    } else {
+      ret[key] = [];
+    }
+  }
+
+  {
+    const key = "source";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = utils.tryImplForWrapper(value);
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MimeType.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MimeType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MimeType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,151 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "MimeType";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'MimeType'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["MimeType"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor MimeType is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class MimeType {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of MimeType.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["type"]);
+    }
+
+    get description() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get description' called on an object that is not a valid instance of MimeType.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["description"]);
+    }
+
+    get suffixes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get suffixes' called on an object that is not a valid instance of MimeType.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["suffixes"]);
+    }
+
+    get enabledPlugin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get enabledPlugin' called on an object that is not a valid instance of MimeType.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["enabledPlugin"]);
+    }
+  }
+  Object.defineProperties(MimeType.prototype, {
+    type: { enumerable: true },
+    description: { enumerable: true },
+    suffixes: { enumerable: true },
+    enabledPlugin: { enumerable: true },
+    [Symbol.toStringTag]: { value: "MimeType", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = MimeType;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: MimeType
+  });
+};
+
+const Impl = require("../navigator/MimeType-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MimeTypeArray.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MimeTypeArray.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MimeTypeArray.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,330 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "MimeTypeArray";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'MimeTypeArray'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["MimeTypeArray"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor MimeTypeArray is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class MimeTypeArray {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of MimeTypeArray.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'MimeTypeArray': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'MimeTypeArray': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].item(...args);
+    }
+
+    namedItem(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'namedItem' called on an object that is not a valid instance of MimeTypeArray.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'namedItem' on 'MimeTypeArray': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'namedItem' on 'MimeTypeArray': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].namedItem(...args);
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of MimeTypeArray.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(MimeTypeArray.prototype, {
+    item: { enumerable: true },
+    namedItem: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "MimeTypeArray", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = MimeTypeArray;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: MimeTypeArray
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../navigator/MimeTypeArray-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MouseEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MouseEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MouseEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,463 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const MouseEventInit = require("./MouseEventInit.js");
+const EventTarget = require("./EventTarget.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const UIEvent = require("./UIEvent.js");
+
+const interfaceName = "MouseEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'MouseEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["MouseEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor MouseEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  UIEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.UIEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate MouseEvent before UIEvent");
+  }
+  class MouseEvent extends globalObject.UIEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'MouseEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'MouseEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = MouseEventInit.convert(curArg, { context: "Failed to construct 'MouseEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    getModifierState(keyArg) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getModifierState' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getModifierState' on 'MouseEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getModifierState' on 'MouseEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getModifierState(...args);
+    }
+
+    initMouseEvent(typeArg) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initMouseEvent' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initMouseEvent' on 'MouseEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = utils.tryImplForWrapper(curArg);
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[4];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 5"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[5];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 6"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[6];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 7"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[7];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 8"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[8];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 9"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[9];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 10"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[10];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 11"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[11];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 12"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[12];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 13"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[13];
+        if (curArg !== undefined) {
+          curArg = conversions["short"](curArg, {
+            context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 14"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[14];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = EventTarget.convert(curArg, {
+              context: "Failed to execute 'initMouseEvent' on 'MouseEvent': parameter 15"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initMouseEvent(...args);
+    }
+
+    get screenX() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get screenX' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["screenX"];
+    }
+
+    get screenY() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get screenY' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["screenY"];
+    }
+
+    get clientX() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clientX' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["clientX"];
+    }
+
+    get clientY() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get clientY' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["clientY"];
+    }
+
+    get ctrlKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ctrlKey' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["ctrlKey"];
+    }
+
+    get shiftKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get shiftKey' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["shiftKey"];
+    }
+
+    get altKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get altKey' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["altKey"];
+    }
+
+    get metaKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get metaKey' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["metaKey"];
+    }
+
+    get button() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get button' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["button"];
+    }
+
+    get buttons() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get buttons' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return esValue[implSymbol]["buttons"];
+    }
+
+    get relatedTarget() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get relatedTarget' called on an object that is not a valid instance of MouseEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["relatedTarget"]);
+    }
+  }
+  Object.defineProperties(MouseEvent.prototype, {
+    getModifierState: { enumerable: true },
+    initMouseEvent: { enumerable: true },
+    screenX: { enumerable: true },
+    screenY: { enumerable: true },
+    clientX: { enumerable: true },
+    clientY: { enumerable: true },
+    ctrlKey: { enumerable: true },
+    shiftKey: { enumerable: true },
+    altKey: { enumerable: true },
+    metaKey: { enumerable: true },
+    button: { enumerable: true },
+    buttons: { enumerable: true },
+    relatedTarget: { enumerable: true },
+    [Symbol.toStringTag]: { value: "MouseEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = MouseEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: MouseEvent
+  });
+};
+
+const Impl = require("../events/MouseEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MouseEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MouseEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MouseEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,108 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventTarget = require("./EventTarget.js");
+const EventModifierInit = require("./EventModifierInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventModifierInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "button";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["short"](value, { context: context + " has member 'button' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "buttons";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned short"](value, { context: context + " has member 'buttons' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "clientX";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["long"](value, { context: context + " has member 'clientX' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "clientY";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["long"](value, { context: context + " has member 'clientY' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "relatedTarget";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = EventTarget.convert(value, { context: context + " has member 'relatedTarget' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "screenX";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["long"](value, { context: context + " has member 'screenX' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "screenY";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["long"](value, { context: context + " has member 'screenY' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationCallback.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationCallback.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationCallback.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (typeof value !== "function") {
+    throw new TypeError(context + " is not a function");
+  }
+
+  function invokeTheCallbackFunction(mutations, observer) {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    mutations = utils.tryWrapperForImpl(mutations);
+
+    observer = utils.tryWrapperForImpl(observer);
+
+    callResult = Reflect.apply(value, thisArg, [mutations, observer]);
+  }
+
+  invokeTheCallbackFunction.construct = (mutations, observer) => {
+    mutations = utils.tryWrapperForImpl(mutations);
+
+    observer = utils.tryWrapperForImpl(observer);
+
+    let callResult = Reflect.construct(value, [mutations, observer]);
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationObserver.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationObserver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationObserver.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,171 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const MutationCallback = require("./MutationCallback.js");
+const Node = require("./Node.js");
+const MutationObserverInit = require("./MutationObserverInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "MutationObserver";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'MutationObserver'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["MutationObserver"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor MutationObserver is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class MutationObserver {
+    constructor(callback) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'MutationObserver': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = MutationCallback.convert(curArg, { context: "Failed to construct 'MutationObserver': parameter 1" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    observe(target) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'observe' called on an object that is not a valid instance of MutationObserver.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'observe' on 'MutationObserver': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'observe' on 'MutationObserver': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = MutationObserverInit.convert(curArg, {
+          context: "Failed to execute 'observe' on 'MutationObserver': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].observe(...args);
+    }
+
+    disconnect() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'disconnect' called on an object that is not a valid instance of MutationObserver.");
+      }
+
+      return esValue[implSymbol].disconnect();
+    }
+
+    takeRecords() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'takeRecords' called on an object that is not a valid instance of MutationObserver.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].takeRecords());
+    }
+  }
+  Object.defineProperties(MutationObserver.prototype, {
+    observe: { enumerable: true },
+    disconnect: { enumerable: true },
+    takeRecords: { enumerable: true },
+    [Symbol.toStringTag]: { value: "MutationObserver", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = MutationObserver;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: MutationObserver
+  });
+};
+
+const Impl = require("../mutation-observer/MutationObserver-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationObserverInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationObserverInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationObserverInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,103 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "attributeFilter";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (!utils.isObject(value)) {
+        throw new TypeError(context + " has member 'attributeFilter' that" + " is not an iterable object.");
+      } else {
+        const V = [];
+        const tmp = value;
+        for (let nextItem of tmp) {
+          nextItem = conversions["DOMString"](nextItem, {
+            context: context + " has member 'attributeFilter' that" + "'s element"
+          });
+
+          V.push(nextItem);
+        }
+        value = V;
+      }
+
+      ret[key] = value;
+    }
+  }
+
+  {
+    const key = "attributeOldValue";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'attributeOldValue' that" });
+
+      ret[key] = value;
+    }
+  }
+
+  {
+    const key = "attributes";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'attributes' that" });
+
+      ret[key] = value;
+    }
+  }
+
+  {
+    const key = "characterData";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'characterData' that" });
+
+      ret[key] = value;
+    }
+  }
+
+  {
+    const key = "characterDataOldValue";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'characterDataOldValue' that" });
+
+      ret[key] = value;
+    }
+  }
+
+  {
+    const key = "childList";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'childList' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "subtree";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'subtree' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationRecord.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationRecord.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/MutationRecord.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,216 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "MutationRecord";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'MutationRecord'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["MutationRecord"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor MutationRecord is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class MutationRecord {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return utils.getSameObject(this, "target", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["target"]);
+      });
+    }
+
+    get addedNodes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get addedNodes' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return utils.getSameObject(this, "addedNodes", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["addedNodes"]);
+      });
+    }
+
+    get removedNodes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get removedNodes' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return utils.getSameObject(this, "removedNodes", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["removedNodes"]);
+      });
+    }
+
+    get previousSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get previousSibling' called on an object that is not a valid instance of MutationRecord."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["previousSibling"]);
+    }
+
+    get nextSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nextSibling' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["nextSibling"]);
+    }
+
+    get attributeName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get attributeName' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return esValue[implSymbol]["attributeName"];
+    }
+
+    get attributeNamespace() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get attributeNamespace' called on an object that is not a valid instance of MutationRecord."
+        );
+      }
+
+      return esValue[implSymbol]["attributeNamespace"];
+    }
+
+    get oldValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oldValue' called on an object that is not a valid instance of MutationRecord.");
+      }
+
+      return esValue[implSymbol]["oldValue"];
+    }
+  }
+  Object.defineProperties(MutationRecord.prototype, {
+    type: { enumerable: true },
+    target: { enumerable: true },
+    addedNodes: { enumerable: true },
+    removedNodes: { enumerable: true },
+    previousSibling: { enumerable: true },
+    nextSibling: { enumerable: true },
+    attributeName: { enumerable: true },
+    attributeNamespace: { enumerable: true },
+    oldValue: { enumerable: true },
+    [Symbol.toStringTag]: { value: "MutationRecord", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = MutationRecord;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: MutationRecord
+  });
+};
+
+const Impl = require("../mutation-observer/MutationRecord-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/NamedNodeMap.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/NamedNodeMap.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/NamedNodeMap.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,522 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Attr = require("./Attr.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "NamedNodeMap";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'NamedNodeMap'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["NamedNodeMap"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor NamedNodeMap is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class NamedNodeMap {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'NamedNodeMap': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'NamedNodeMap': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    getNamedItem(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getNamedItem' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getNamedItem' on 'NamedNodeMap': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getNamedItem' on 'NamedNodeMap': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getNamedItem(...args));
+    }
+
+    getNamedItemNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getNamedItemNS' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'getNamedItemNS' on 'NamedNodeMap': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'getNamedItemNS' on 'NamedNodeMap': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getNamedItemNS' on 'NamedNodeMap': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getNamedItemNS(...args));
+    }
+
+    setNamedItem(attr) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setNamedItem' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setNamedItem' on 'NamedNodeMap': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Attr.convert(curArg, { context: "Failed to execute 'setNamedItem' on 'NamedNodeMap': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].setNamedItem(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    setNamedItemNS(attr) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setNamedItemNS' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setNamedItemNS' on 'NamedNodeMap': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Attr.convert(curArg, { context: "Failed to execute 'setNamedItemNS' on 'NamedNodeMap': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].setNamedItemNS(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    removeNamedItem(qualifiedName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeNamedItem' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeNamedItem' on 'NamedNodeMap': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'removeNamedItem' on 'NamedNodeMap': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].removeNamedItem(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    removeNamedItemNS(namespace, localName) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeNamedItemNS' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'removeNamedItemNS' on 'NamedNodeMap': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'removeNamedItemNS' on 'NamedNodeMap': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'removeNamedItemNS' on 'NamedNodeMap': parameter 2"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].removeNamedItemNS(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of NamedNodeMap.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(NamedNodeMap.prototype, {
+    item: { enumerable: true },
+    getNamedItem: { enumerable: true },
+    getNamedItemNS: { enumerable: true },
+    setNamedItem: { enumerable: true },
+    setNamedItemNS: { enumerable: true },
+    removeNamedItem: { enumerable: true },
+    removeNamedItemNS: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "NamedNodeMap", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = NamedNodeMap;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: NamedNodeMap
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of target[implSymbol][utils.supportedPropertyNames]) {
+      if (!(key in target)) {
+        keys.add(`${key}`);
+      }
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    const namedValue = target[implSymbol].getNamedItem(P);
+
+    if (namedValue !== null && !(P in target) && !ignoreNamedProps) {
+      return {
+        writable: false,
+        enumerable: false,
+        configurable: true,
+        value: utils.tryWrapperForImpl(namedValue)
+      };
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+    if (!utils.hasOwn(target, P)) {
+      const creating = !(target[implSymbol].getNamedItem(P) !== null);
+      if (!creating) {
+        return false;
+      }
+    }
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    if (target[implSymbol].getNamedItem(P) !== null && !(P in target)) {
+      return false;
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../attributes/NamedNodeMap-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Navigator.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Navigator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Navigator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,297 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Navigator";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Navigator'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Navigator"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Navigator is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Navigator {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    javaEnabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'javaEnabled' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol].javaEnabled();
+    }
+
+    get appCodeName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get appCodeName' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["appCodeName"];
+    }
+
+    get appName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get appName' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["appName"];
+    }
+
+    get appVersion() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get appVersion' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["appVersion"];
+    }
+
+    get platform() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get platform' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["platform"];
+    }
+
+    get product() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get product' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["product"];
+    }
+
+    get productSub() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get productSub' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["productSub"];
+    }
+
+    get userAgent() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get userAgent' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["userAgent"];
+    }
+
+    get vendor() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vendor' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["vendor"];
+    }
+
+    get vendorSub() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get vendorSub' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["vendorSub"];
+    }
+
+    get language() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get language' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["language"];
+    }
+
+    get languages() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get languages' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["languages"]);
+    }
+
+    get onLine() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onLine' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["onLine"];
+    }
+
+    get cookieEnabled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get cookieEnabled' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["cookieEnabled"];
+    }
+
+    get plugins() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get plugins' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return utils.getSameObject(this, "plugins", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["plugins"]);
+      });
+    }
+
+    get mimeTypes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get mimeTypes' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return utils.getSameObject(this, "mimeTypes", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["mimeTypes"]);
+      });
+    }
+
+    get hardwareConcurrency() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get hardwareConcurrency' called on an object that is not a valid instance of Navigator.");
+      }
+
+      return esValue[implSymbol]["hardwareConcurrency"];
+    }
+  }
+  Object.defineProperties(Navigator.prototype, {
+    javaEnabled: { enumerable: true },
+    appCodeName: { enumerable: true },
+    appName: { enumerable: true },
+    appVersion: { enumerable: true },
+    platform: { enumerable: true },
+    product: { enumerable: true },
+    productSub: { enumerable: true },
+    userAgent: { enumerable: true },
+    vendor: { enumerable: true },
+    vendorSub: { enumerable: true },
+    language: { enumerable: true },
+    languages: { enumerable: true },
+    onLine: { enumerable: true },
+    cookieEnabled: { enumerable: true },
+    plugins: { enumerable: true },
+    mimeTypes: { enumerable: true },
+    hardwareConcurrency: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Navigator", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Navigator;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Navigator
+  });
+};
+
+const Impl = require("../navigator/Navigator-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Node.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Node.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Node.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,736 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const GetRootNodeOptions = require("./GetRootNodeOptions.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const EventTarget = require("./EventTarget.js");
+
+const interfaceName = "Node";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Node'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Node"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Node is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  EventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.EventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate Node before EventTarget");
+  }
+  class Node extends globalObject.EventTarget {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    getRootNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getRootNode' called on an object that is not a valid instance of Node.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = GetRootNodeOptions.convert(curArg, {
+          context: "Failed to execute 'getRootNode' on 'Node': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getRootNode(...args));
+    }
+
+    hasChildNodes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'hasChildNodes' called on an object that is not a valid instance of Node.");
+      }
+
+      return esValue[implSymbol].hasChildNodes();
+    }
+
+    normalize() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'normalize' called on an object that is not a valid instance of Node.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].normalize();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    cloneNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'cloneNode' called on an object that is not a valid instance of Node.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, { context: "Failed to execute 'cloneNode' on 'Node': parameter 1" });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].cloneNode(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    isEqualNode(otherNode) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'isEqualNode' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'isEqualNode' on 'Node': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = exports.convert(curArg, { context: "Failed to execute 'isEqualNode' on 'Node': parameter 1" });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].isEqualNode(...args);
+    }
+
+    isSameNode(otherNode) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'isSameNode' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'isSameNode' on 'Node': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = exports.convert(curArg, { context: "Failed to execute 'isSameNode' on 'Node': parameter 1" });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].isSameNode(...args);
+    }
+
+    compareDocumentPosition(other) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'compareDocumentPosition' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'compareDocumentPosition' on 'Node': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = exports.convert(curArg, {
+          context: "Failed to execute 'compareDocumentPosition' on 'Node': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].compareDocumentPosition(...args);
+    }
+
+    contains(other) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'contains' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'contains' on 'Node': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = exports.convert(curArg, { context: "Failed to execute 'contains' on 'Node': parameter 1" });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].contains(...args);
+    }
+
+    lookupPrefix(namespace) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'lookupPrefix' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'lookupPrefix' on 'Node': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'lookupPrefix' on 'Node': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].lookupPrefix(...args);
+    }
+
+    lookupNamespaceURI(prefix) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'lookupNamespaceURI' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'lookupNamespaceURI' on 'Node': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'lookupNamespaceURI' on 'Node': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].lookupNamespaceURI(...args);
+    }
+
+    isDefaultNamespace(namespace) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'isDefaultNamespace' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'isDefaultNamespace' on 'Node': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = conversions["DOMString"](curArg, {
+            context: "Failed to execute 'isDefaultNamespace' on 'Node': parameter 1"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].isDefaultNamespace(...args);
+    }
+
+    insertBefore(node, child) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertBefore' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'insertBefore' on 'Node': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = exports.convert(curArg, { context: "Failed to execute 'insertBefore' on 'Node': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = exports.convert(curArg, { context: "Failed to execute 'insertBefore' on 'Node': parameter 2" });
+        }
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].insertBefore(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    appendChild(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'appendChild' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'appendChild' on 'Node': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = exports.convert(curArg, { context: "Failed to execute 'appendChild' on 'Node': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].appendChild(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    replaceChild(node, child) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceChild' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'replaceChild' on 'Node': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = exports.convert(curArg, { context: "Failed to execute 'replaceChild' on 'Node': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = exports.convert(curArg, { context: "Failed to execute 'replaceChild' on 'Node': parameter 2" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].replaceChild(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    removeChild(child) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeChild' called on an object that is not a valid instance of Node.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeChild' on 'Node': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = exports.convert(curArg, { context: "Failed to execute 'removeChild' on 'Node': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].removeChild(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get nodeType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nodeType' called on an object that is not a valid instance of Node.");
+      }
+
+      return esValue[implSymbol]["nodeType"];
+    }
+
+    get nodeName() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nodeName' called on an object that is not a valid instance of Node.");
+      }
+
+      return esValue[implSymbol]["nodeName"];
+    }
+
+    get baseURI() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get baseURI' called on an object that is not a valid instance of Node.");
+      }
+
+      return esValue[implSymbol]["baseURI"];
+    }
+
+    get isConnected() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get isConnected' called on an object that is not a valid instance of Node.");
+      }
+
+      return esValue[implSymbol]["isConnected"];
+    }
+
+    get ownerDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ownerDocument' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ownerDocument"]);
+    }
+
+    get parentNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get parentNode' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["parentNode"]);
+    }
+
+    get parentElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get parentElement' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["parentElement"]);
+    }
+
+    get childNodes() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get childNodes' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.getSameObject(this, "childNodes", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["childNodes"]);
+      });
+    }
+
+    get firstChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get firstChild' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["firstChild"]);
+    }
+
+    get lastChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get lastChild' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["lastChild"]);
+    }
+
+    get previousSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get previousSibling' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["previousSibling"]);
+    }
+
+    get nextSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nextSibling' called on an object that is not a valid instance of Node.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["nextSibling"]);
+    }
+
+    get nodeValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nodeValue' called on an object that is not a valid instance of Node.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["nodeValue"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set nodeValue(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set nodeValue' called on an object that is not a valid instance of Node.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'nodeValue' property on 'Node': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["nodeValue"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get textContent() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get textContent' called on an object that is not a valid instance of Node.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["textContent"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set textContent(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set textContent' called on an object that is not a valid instance of Node.");
+      }
+
+      if (V === null || V === undefined) {
+        V = null;
+      } else {
+        V = conversions["DOMString"](V, {
+          context: "Failed to set the 'textContent' property on 'Node': The provided value"
+        });
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["textContent"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(Node.prototype, {
+    getRootNode: { enumerable: true },
+    hasChildNodes: { enumerable: true },
+    normalize: { enumerable: true },
+    cloneNode: { enumerable: true },
+    isEqualNode: { enumerable: true },
+    isSameNode: { enumerable: true },
+    compareDocumentPosition: { enumerable: true },
+    contains: { enumerable: true },
+    lookupPrefix: { enumerable: true },
+    lookupNamespaceURI: { enumerable: true },
+    isDefaultNamespace: { enumerable: true },
+    insertBefore: { enumerable: true },
+    appendChild: { enumerable: true },
+    replaceChild: { enumerable: true },
+    removeChild: { enumerable: true },
+    nodeType: { enumerable: true },
+    nodeName: { enumerable: true },
+    baseURI: { enumerable: true },
+    isConnected: { enumerable: true },
+    ownerDocument: { enumerable: true },
+    parentNode: { enumerable: true },
+    parentElement: { enumerable: true },
+    childNodes: { enumerable: true },
+    firstChild: { enumerable: true },
+    lastChild: { enumerable: true },
+    previousSibling: { enumerable: true },
+    nextSibling: { enumerable: true },
+    nodeValue: { enumerable: true },
+    textContent: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Node", configurable: true },
+    ELEMENT_NODE: { value: 1, enumerable: true },
+    ATTRIBUTE_NODE: { value: 2, enumerable: true },
+    TEXT_NODE: { value: 3, enumerable: true },
+    CDATA_SECTION_NODE: { value: 4, enumerable: true },
+    ENTITY_REFERENCE_NODE: { value: 5, enumerable: true },
+    ENTITY_NODE: { value: 6, enumerable: true },
+    PROCESSING_INSTRUCTION_NODE: { value: 7, enumerable: true },
+    COMMENT_NODE: { value: 8, enumerable: true },
+    DOCUMENT_NODE: { value: 9, enumerable: true },
+    DOCUMENT_TYPE_NODE: { value: 10, enumerable: true },
+    DOCUMENT_FRAGMENT_NODE: { value: 11, enumerable: true },
+    NOTATION_NODE: { value: 12, enumerable: true },
+    DOCUMENT_POSITION_DISCONNECTED: { value: 0x01, enumerable: true },
+    DOCUMENT_POSITION_PRECEDING: { value: 0x02, enumerable: true },
+    DOCUMENT_POSITION_FOLLOWING: { value: 0x04, enumerable: true },
+    DOCUMENT_POSITION_CONTAINS: { value: 0x08, enumerable: true },
+    DOCUMENT_POSITION_CONTAINED_BY: { value: 0x10, enumerable: true },
+    DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: { value: 0x20, enumerable: true }
+  });
+  Object.defineProperties(Node, {
+    ELEMENT_NODE: { value: 1, enumerable: true },
+    ATTRIBUTE_NODE: { value: 2, enumerable: true },
+    TEXT_NODE: { value: 3, enumerable: true },
+    CDATA_SECTION_NODE: { value: 4, enumerable: true },
+    ENTITY_REFERENCE_NODE: { value: 5, enumerable: true },
+    ENTITY_NODE: { value: 6, enumerable: true },
+    PROCESSING_INSTRUCTION_NODE: { value: 7, enumerable: true },
+    COMMENT_NODE: { value: 8, enumerable: true },
+    DOCUMENT_NODE: { value: 9, enumerable: true },
+    DOCUMENT_TYPE_NODE: { value: 10, enumerable: true },
+    DOCUMENT_FRAGMENT_NODE: { value: 11, enumerable: true },
+    NOTATION_NODE: { value: 12, enumerable: true },
+    DOCUMENT_POSITION_DISCONNECTED: { value: 0x01, enumerable: true },
+    DOCUMENT_POSITION_PRECEDING: { value: 0x02, enumerable: true },
+    DOCUMENT_POSITION_FOLLOWING: { value: 0x04, enumerable: true },
+    DOCUMENT_POSITION_CONTAINS: { value: 0x08, enumerable: true },
+    DOCUMENT_POSITION_CONTAINED_BY: { value: 0x10, enumerable: true },
+    DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: { value: 0x20, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Node;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Node
+  });
+};
+
+const Impl = require("../nodes/Node-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeFilter.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeFilter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeFilter.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,74 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  if (!utils.isObject(value)) {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  function callTheUserObjectsOperation(node) {
+    let thisArg = utils.tryWrapperForImpl(this);
+    let O = value;
+    let X = O;
+
+    if (typeof O !== "function") {
+      X = O["acceptNode"];
+      if (typeof X !== "function") {
+        throw new TypeError(`${context} does not correctly implement NodeFilter.`);
+      }
+      thisArg = O;
+    }
+
+    node = utils.tryWrapperForImpl(node);
+
+    let callResult = Reflect.apply(X, thisArg, [node]);
+
+    callResult = conversions["unsigned short"](callResult, { context: context });
+
+    return callResult;
+  }
+
+  callTheUserObjectsOperation[utils.wrapperSymbol] = value;
+  callTheUserObjectsOperation.objectReference = value;
+
+  return callTheUserObjectsOperation;
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  const NodeFilter = () => {
+    throw new TypeError("Illegal invocation");
+  };
+
+  Object.defineProperties(NodeFilter, {
+    FILTER_ACCEPT: { value: 1, enumerable: true },
+    FILTER_REJECT: { value: 2, enumerable: true },
+    FILTER_SKIP: { value: 3, enumerable: true },
+    SHOW_ALL: { value: 0xffffffff, enumerable: true },
+    SHOW_ELEMENT: { value: 0x1, enumerable: true },
+    SHOW_ATTRIBUTE: { value: 0x2, enumerable: true },
+    SHOW_TEXT: { value: 0x4, enumerable: true },
+    SHOW_CDATA_SECTION: { value: 0x8, enumerable: true },
+    SHOW_ENTITY_REFERENCE: { value: 0x10, enumerable: true },
+    SHOW_ENTITY: { value: 0x20, enumerable: true },
+    SHOW_PROCESSING_INSTRUCTION: { value: 0x40, enumerable: true },
+    SHOW_COMMENT: { value: 0x80, enumerable: true },
+    SHOW_DOCUMENT: { value: 0x100, enumerable: true },
+    SHOW_DOCUMENT_TYPE: { value: 0x200, enumerable: true },
+    SHOW_DOCUMENT_FRAGMENT: { value: 0x400, enumerable: true },
+    SHOW_NOTATION: { value: 0x800, enumerable: true }
+  });
+
+  Object.defineProperty(globalObject, "NodeFilter", {
+    configurable: true,
+    writable: true,
+    value: NodeFilter
+  });
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeIterator.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeIterator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeIterator.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,196 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "NodeIterator";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'NodeIterator'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["NodeIterator"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor NodeIterator is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class NodeIterator {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    nextNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'nextNode' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].nextNode());
+    }
+
+    previousNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'previousNode' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].previousNode());
+    }
+
+    detach() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'detach' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return esValue[implSymbol].detach();
+    }
+
+    get root() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get root' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return utils.getSameObject(this, "root", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["root"]);
+      });
+    }
+
+    get referenceNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get referenceNode' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["referenceNode"]);
+    }
+
+    get pointerBeforeReferenceNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get pointerBeforeReferenceNode' called on an object that is not a valid instance of NodeIterator."
+        );
+      }
+
+      return esValue[implSymbol]["pointerBeforeReferenceNode"];
+    }
+
+    get whatToShow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get whatToShow' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return esValue[implSymbol]["whatToShow"];
+    }
+
+    get filter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get filter' called on an object that is not a valid instance of NodeIterator.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["filter"]);
+    }
+  }
+  Object.defineProperties(NodeIterator.prototype, {
+    nextNode: { enumerable: true },
+    previousNode: { enumerable: true },
+    detach: { enumerable: true },
+    root: { enumerable: true },
+    referenceNode: { enumerable: true },
+    pointerBeforeReferenceNode: { enumerable: true },
+    whatToShow: { enumerable: true },
+    filter: { enumerable: true },
+    [Symbol.toStringTag]: { value: "NodeIterator", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = NodeIterator;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: NodeIterator
+  });
+};
+
+const Impl = require("../traversal/NodeIterator-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeList.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/NodeList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,309 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "NodeList";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'NodeList'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["NodeList"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor NodeList is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class NodeList {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of NodeList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'NodeList': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'NodeList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of NodeList.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(NodeList.prototype, {
+    item: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "NodeList", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true },
+    keys: { value: Array.prototype.keys, configurable: true, enumerable: true, writable: true },
+    values: { value: Array.prototype[Symbol.iterator], configurable: true, enumerable: true, writable: true },
+    entries: { value: Array.prototype.entries, configurable: true, enumerable: true, writable: true },
+    forEach: { value: Array.prototype.forEach, configurable: true, enumerable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = NodeList;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: NodeList
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../nodes/NodeList-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/OnBeforeUnloadEventHandlerNonNull.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/OnBeforeUnloadEventHandlerNonNull.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/OnBeforeUnloadEventHandlerNonNull.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  function invokeTheCallbackFunction(event) {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    if (typeof value === "function") {
+      event = utils.tryWrapperForImpl(event);
+
+      callResult = Reflect.apply(value, thisArg, [event]);
+    }
+
+    if (callResult === null || callResult === undefined) {
+      callResult = null;
+    } else {
+      callResult = conversions["DOMString"](callResult, { context: context });
+    }
+    return callResult;
+  }
+
+  invokeTheCallbackFunction.construct = event => {
+    event = utils.tryWrapperForImpl(event);
+
+    let callResult = Reflect.construct(value, [event]);
+
+    if (callResult === null || callResult === undefined) {
+      callResult = null;
+    } else {
+      callResult = conversions["DOMString"](callResult, { context: context });
+    }
+    return callResult;
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/OnErrorEventHandlerNonNull.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/OnErrorEventHandlerNonNull.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/OnErrorEventHandlerNonNull.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,60 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  function invokeTheCallbackFunction(...args) {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    if (typeof value === "function") {
+      for (let i = 0; i < Math.min(args.length, 5); i++) {
+        args[i] = utils.tryWrapperForImpl(args[i]);
+      }
+
+      if (args.length < 1) {
+        for (let i = args.length; i < 1; i++) {
+          args[i] = undefined;
+        }
+      } else if (args.length > 5) {
+        args.length = 5;
+      }
+
+      callResult = Reflect.apply(value, thisArg, args);
+    }
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  }
+
+  invokeTheCallbackFunction.construct = (...args) => {
+    for (let i = 0; i < Math.min(args.length, 5); i++) {
+      args[i] = utils.tryWrapperForImpl(args[i]);
+    }
+
+    if (args.length < 1) {
+      for (let i = args.length; i < 1; i++) {
+        args[i] = undefined;
+      }
+    } else if (args.length > 5) {
+      args.length = 5;
+    }
+
+    let callResult = Reflect.construct(value, args);
+
+    callResult = conversions["any"](callResult, { context: context });
+
+    return callResult;
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/PageTransitionEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/PageTransitionEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/PageTransitionEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,146 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const PageTransitionEventInit = require("./PageTransitionEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "PageTransitionEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'PageTransitionEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["PageTransitionEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor PageTransitionEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate PageTransitionEvent before Event");
+  }
+  class PageTransitionEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'PageTransitionEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to construct 'PageTransitionEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = PageTransitionEventInit.convert(curArg, {
+          context: "Failed to construct 'PageTransitionEvent': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get persisted() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get persisted' called on an object that is not a valid instance of PageTransitionEvent.");
+      }
+
+      return esValue[implSymbol]["persisted"];
+    }
+  }
+  Object.defineProperties(PageTransitionEvent.prototype, {
+    persisted: { enumerable: true },
+    [Symbol.toStringTag]: { value: "PageTransitionEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = PageTransitionEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: PageTransitionEvent
+  });
+};
+
+const Impl = require("../events/PageTransitionEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/PageTransitionEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/PageTransitionEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/PageTransitionEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "persisted";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'persisted' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Performance.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Performance.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Performance.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,145 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const EventTarget = require("./EventTarget.js");
+
+const interfaceName = "Performance";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Performance'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Performance"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Performance is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  EventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.EventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate Performance before EventTarget");
+  }
+  class Performance extends globalObject.EventTarget {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    now() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'now' called on an object that is not a valid instance of Performance.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].now());
+    }
+
+    toJSON() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toJSON' called on an object that is not a valid instance of Performance.");
+      }
+
+      return esValue[implSymbol].toJSON();
+    }
+
+    get timeOrigin() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get timeOrigin' called on an object that is not a valid instance of Performance.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["timeOrigin"]);
+    }
+  }
+  Object.defineProperties(Performance.prototype, {
+    now: { enumerable: true },
+    toJSON: { enumerable: true },
+    timeOrigin: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Performance", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Performance;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Performance
+  });
+};
+
+const Impl = require("../hr-time/Performance-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Plugin.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Plugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Plugin.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,361 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Plugin";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Plugin'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Plugin"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Plugin is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Plugin {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of Plugin.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'Plugin': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, { context: "Failed to execute 'item' on 'Plugin': parameter 1" });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    namedItem(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'namedItem' called on an object that is not a valid instance of Plugin.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'namedItem' on 'Plugin': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'namedItem' on 'Plugin': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].namedItem(...args));
+    }
+
+    get name() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get name' called on an object that is not a valid instance of Plugin.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["name"]);
+    }
+
+    get description() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get description' called on an object that is not a valid instance of Plugin.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["description"]);
+    }
+
+    get filename() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get filename' called on an object that is not a valid instance of Plugin.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["filename"]);
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of Plugin.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["length"]);
+    }
+  }
+  Object.defineProperties(Plugin.prototype, {
+    item: { enumerable: true },
+    namedItem: { enumerable: true },
+    name: { enumerable: true },
+    description: { enumerable: true },
+    filename: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Plugin", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Plugin;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Plugin
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+
+      if (target[implSymbol][utils.supportsPropertyIndex](index)) {
+        const indexedValue = target[implSymbol].item(index);
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+
+      if (target[implSymbol][utils.supportsPropertyIndex](index)) {
+        const indexedValue = target[implSymbol].item(index);
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !target[implSymbol][utils.supportsPropertyIndex](index);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../navigator/Plugin-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/PluginArray.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/PluginArray.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/PluginArray.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,340 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "PluginArray";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'PluginArray'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["PluginArray"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor PluginArray is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class PluginArray {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    refresh() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'refresh' called on an object that is not a valid instance of PluginArray.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].refresh());
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of PluginArray.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'PluginArray': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'PluginArray': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].item(...args);
+    }
+
+    namedItem(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'namedItem' called on an object that is not a valid instance of PluginArray.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'namedItem' on 'PluginArray': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'namedItem' on 'PluginArray': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].namedItem(...args);
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of PluginArray.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(PluginArray.prototype, {
+    refresh: { enumerable: true },
+    item: { enumerable: true },
+    namedItem: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "PluginArray", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = PluginArray;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: PluginArray
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../navigator/PluginArray-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/PopStateEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/PopStateEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/PopStateEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,142 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const PopStateEventInit = require("./PopStateEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "PopStateEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'PopStateEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["PopStateEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor PopStateEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate PopStateEvent before Event");
+  }
+  class PopStateEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'PopStateEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'PopStateEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = PopStateEventInit.convert(curArg, { context: "Failed to construct 'PopStateEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get state() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get state' called on an object that is not a valid instance of PopStateEvent.");
+      }
+
+      return esValue[implSymbol]["state"];
+    }
+  }
+  Object.defineProperties(PopStateEvent.prototype, {
+    state: { enumerable: true },
+    [Symbol.toStringTag]: { value: "PopStateEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = PopStateEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: PopStateEvent
+  });
+};
+
+const Impl = require("../events/PopStateEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/PopStateEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/PopStateEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/PopStateEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "state";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["any"](value, { context: context + " has member 'state' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ProcessingInstruction.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ProcessingInstruction.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ProcessingInstruction.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,125 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const CharacterData = require("./CharacterData.js");
+
+const interfaceName = "ProcessingInstruction";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'ProcessingInstruction'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["ProcessingInstruction"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor ProcessingInstruction is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  CharacterData._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.CharacterData === undefined) {
+    throw new Error("Internal error: attempting to evaluate ProcessingInstruction before CharacterData");
+  }
+  class ProcessingInstruction extends globalObject.CharacterData {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get target() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get target' called on an object that is not a valid instance of ProcessingInstruction.");
+      }
+
+      return esValue[implSymbol]["target"];
+    }
+  }
+  Object.defineProperties(ProcessingInstruction.prototype, {
+    target: { enumerable: true },
+    [Symbol.toStringTag]: { value: "ProcessingInstruction", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = ProcessingInstruction;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: ProcessingInstruction
+  });
+};
+
+const Impl = require("../nodes/ProcessingInstruction-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ProgressEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ProgressEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ProgressEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,166 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ProgressEventInit = require("./ProgressEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "ProgressEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'ProgressEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["ProgressEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor ProgressEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "DedicatedWorker", "SharedWorker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate ProgressEvent before Event");
+  }
+  class ProgressEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'ProgressEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'ProgressEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = ProgressEventInit.convert(curArg, { context: "Failed to construct 'ProgressEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get lengthComputable() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get lengthComputable' called on an object that is not a valid instance of ProgressEvent."
+        );
+      }
+
+      return esValue[implSymbol]["lengthComputable"];
+    }
+
+    get loaded() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get loaded' called on an object that is not a valid instance of ProgressEvent.");
+      }
+
+      return esValue[implSymbol]["loaded"];
+    }
+
+    get total() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get total' called on an object that is not a valid instance of ProgressEvent.");
+      }
+
+      return esValue[implSymbol]["total"];
+    }
+  }
+  Object.defineProperties(ProgressEvent.prototype, {
+    lengthComputable: { enumerable: true },
+    loaded: { enumerable: true },
+    total: { enumerable: true },
+    [Symbol.toStringTag]: { value: "ProgressEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = ProgressEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: ProgressEvent
+  });
+};
+
+const Impl = require("../events/ProgressEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ProgressEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ProgressEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ProgressEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,56 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "lengthComputable";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'lengthComputable' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "loaded";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long long"](value, { context: context + " has member 'loaded' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "total";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long long"](value, { context: context + " has member 'total' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Range.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Range.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Range.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,619 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const AbstractRange = require("./AbstractRange.js");
+
+const interfaceName = "Range";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Range'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Range"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Range is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  AbstractRange._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.AbstractRange === undefined) {
+    throw new Error("Internal error: attempting to evaluate Range before AbstractRange");
+  }
+  class Range extends globalObject.AbstractRange {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    setStart(node, offset) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setStart' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setStart' on 'Range': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setStart' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setStart' on 'Range': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setStart(...args);
+    }
+
+    setEnd(node, offset) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setEnd' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setEnd' on 'Range': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setEnd' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setEnd' on 'Range': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setEnd(...args);
+    }
+
+    setStartBefore(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setStartBefore' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setStartBefore' on 'Range': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setStartBefore' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setStartBefore(...args);
+    }
+
+    setStartAfter(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setStartAfter' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setStartAfter' on 'Range': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setStartAfter' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setStartAfter(...args);
+    }
+
+    setEndBefore(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setEndBefore' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setEndBefore' on 'Range': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setEndBefore' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setEndBefore(...args);
+    }
+
+    setEndAfter(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setEndAfter' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setEndAfter' on 'Range': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setEndAfter' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setEndAfter(...args);
+    }
+
+    collapse() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'collapse' called on an object that is not a valid instance of Range.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, { context: "Failed to execute 'collapse' on 'Range': parameter 1" });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].collapse(...args);
+    }
+
+    selectNode(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'selectNode' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'selectNode' on 'Range': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'selectNode' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].selectNode(...args);
+    }
+
+    selectNodeContents(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'selectNodeContents' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'selectNodeContents' on 'Range': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'selectNodeContents' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].selectNodeContents(...args);
+    }
+
+    compareBoundaryPoints(how, sourceRange) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'compareBoundaryPoints' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'compareBoundaryPoints' on 'Range': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned short"](curArg, {
+          context: "Failed to execute 'compareBoundaryPoints' on 'Range': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = exports.convert(curArg, {
+          context: "Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].compareBoundaryPoints(...args);
+    }
+
+    deleteContents() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteContents' called on an object that is not a valid instance of Range.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteContents();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    extractContents() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'extractContents' called on an object that is not a valid instance of Range.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].extractContents());
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    cloneContents() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'cloneContents' called on an object that is not a valid instance of Range.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].cloneContents());
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    insertNode(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertNode' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'insertNode' on 'Range': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'insertNode' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].insertNode(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    surroundContents(newParent) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'surroundContents' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'surroundContents' on 'Range': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'surroundContents' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].surroundContents(...args);
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    cloneRange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'cloneRange' called on an object that is not a valid instance of Range.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].cloneRange());
+    }
+
+    detach() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'detach' called on an object that is not a valid instance of Range.");
+      }
+
+      return esValue[implSymbol].detach();
+    }
+
+    isPointInRange(node, offset) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'isPointInRange' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'isPointInRange' on 'Range': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'isPointInRange' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'isPointInRange' on 'Range': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].isPointInRange(...args);
+    }
+
+    comparePoint(node, offset) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'comparePoint' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'comparePoint' on 'Range': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'comparePoint' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'comparePoint' on 'Range': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].comparePoint(...args);
+    }
+
+    intersectsNode(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'intersectsNode' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'intersectsNode' on 'Range': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'intersectsNode' on 'Range': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].intersectsNode(...args);
+    }
+
+    toString() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toString' called on an object that is not a valid instance of Range.");
+      }
+
+      return esValue[implSymbol].toString();
+    }
+
+    createContextualFragment(fragment) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createContextualFragment' called on an object that is not a valid instance of Range.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'createContextualFragment' on 'Range': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'createContextualFragment' on 'Range': parameter 1"
+        });
+        args.push(curArg);
+      }
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return utils.tryWrapperForImpl(esValue[implSymbol].createContextualFragment(...args));
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get commonAncestorContainer() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get commonAncestorContainer' called on an object that is not a valid instance of Range.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["commonAncestorContainer"]);
+    }
+  }
+  Object.defineProperties(Range.prototype, {
+    setStart: { enumerable: true },
+    setEnd: { enumerable: true },
+    setStartBefore: { enumerable: true },
+    setStartAfter: { enumerable: true },
+    setEndBefore: { enumerable: true },
+    setEndAfter: { enumerable: true },
+    collapse: { enumerable: true },
+    selectNode: { enumerable: true },
+    selectNodeContents: { enumerable: true },
+    compareBoundaryPoints: { enumerable: true },
+    deleteContents: { enumerable: true },
+    extractContents: { enumerable: true },
+    cloneContents: { enumerable: true },
+    insertNode: { enumerable: true },
+    surroundContents: { enumerable: true },
+    cloneRange: { enumerable: true },
+    detach: { enumerable: true },
+    isPointInRange: { enumerable: true },
+    comparePoint: { enumerable: true },
+    intersectsNode: { enumerable: true },
+    toString: { enumerable: true },
+    createContextualFragment: { enumerable: true },
+    commonAncestorContainer: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Range", configurable: true },
+    START_TO_START: { value: 0, enumerable: true },
+    START_TO_END: { value: 1, enumerable: true },
+    END_TO_END: { value: 2, enumerable: true },
+    END_TO_START: { value: 3, enumerable: true }
+  });
+  Object.defineProperties(Range, {
+    START_TO_START: { value: 0, enumerable: true },
+    START_TO_END: { value: 1, enumerable: true },
+    END_TO_END: { value: 2, enumerable: true },
+    END_TO_START: { value: 3, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Range;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Range
+  });
+};
+
+const Impl = require("../range/Range-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGAnimatedString.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGAnimatedString.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGAnimatedString.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,143 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "SVGAnimatedString";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGAnimatedString'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGAnimatedString"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGAnimatedString is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class SVGAnimatedString {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get baseVal() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get baseVal' called on an object that is not a valid instance of SVGAnimatedString.");
+      }
+
+      return esValue[implSymbol]["baseVal"];
+    }
+
+    set baseVal(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set baseVal' called on an object that is not a valid instance of SVGAnimatedString.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'baseVal' property on 'SVGAnimatedString': The provided value"
+      });
+
+      esValue[implSymbol]["baseVal"] = V;
+    }
+
+    get animVal() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get animVal' called on an object that is not a valid instance of SVGAnimatedString.");
+      }
+
+      return esValue[implSymbol]["animVal"];
+    }
+  }
+  Object.defineProperties(SVGAnimatedString.prototype, {
+    baseVal: { enumerable: true },
+    animVal: { enumerable: true },
+    [Symbol.toStringTag]: { value: "SVGAnimatedString", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGAnimatedString;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGAnimatedString
+  });
+};
+
+const Impl = require("../svg/SVGAnimatedString-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGBoundingBoxOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGBoundingBoxOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGBoundingBoxOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "clipped";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'clipped' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "fill";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'fill' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = true;
+    }
+  }
+
+  {
+    const key = "markers";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'markers' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+
+  {
+    const key = "stroke";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["boolean"](value, { context: context + " has member 'stroke' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = false;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1986 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const OnErrorEventHandlerNonNull = require("./OnErrorEventHandlerNonNull.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Element = require("./Element.js");
+
+const interfaceName = "SVGElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Element._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Element === undefined) {
+    throw new Error("Internal error: attempting to evaluate SVGElement before Element");
+  }
+  class SVGElement extends globalObject.Element {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    focus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'focus' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return esValue[implSymbol].focus();
+    }
+
+    blur() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'blur' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return esValue[implSymbol].blur();
+    }
+
+    get className() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get className' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.getSameObject(this, "className", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["className"]);
+      });
+    }
+
+    get ownerSVGElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ownerSVGElement' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ownerSVGElement"]);
+    }
+
+    get viewportElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get viewportElement' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["viewportElement"]);
+    }
+
+    get style() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get style' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.getSameObject(this, "style", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["style"]);
+      });
+    }
+
+    set style(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set style' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      const Q = esValue["style"];
+      if (!utils.isObject(Q)) {
+        throw new TypeError("Property 'style' is not an object");
+      }
+      Reflect.set(Q, "cssText", V);
+    }
+
+    get onabort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onabort' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onabort"]);
+    }
+
+    set onabort(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onabort' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onabort' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onabort"] = V;
+    }
+
+    get onauxclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onauxclick' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onauxclick"]);
+    }
+
+    set onauxclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onauxclick' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onauxclick' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onauxclick"] = V;
+    }
+
+    get onblur() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onblur' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onblur"]);
+    }
+
+    set onblur(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onblur' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onblur' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onblur"] = V;
+    }
+
+    get oncancel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncancel' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncancel"]);
+    }
+
+    set oncancel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncancel' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncancel' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncancel"] = V;
+    }
+
+    get oncanplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncanplay' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncanplay"]);
+    }
+
+    set oncanplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncanplay' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncanplay' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncanplay"] = V;
+    }
+
+    get oncanplaythrough() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncanplaythrough' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncanplaythrough"]);
+    }
+
+    set oncanplaythrough(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncanplaythrough' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncanplaythrough' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncanplaythrough"] = V;
+    }
+
+    get onchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onchange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onchange"]);
+    }
+
+    set onchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onchange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onchange' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onchange"] = V;
+    }
+
+    get onclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclick' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclick"]);
+    }
+
+    set onclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclick' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclick' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclick"] = V;
+    }
+
+    get onclose() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclose' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclose"]);
+    }
+
+    set onclose(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclose' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclose' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclose"] = V;
+    }
+
+    get oncontextmenu() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncontextmenu' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncontextmenu"]);
+    }
+
+    set oncontextmenu(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncontextmenu' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncontextmenu' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncontextmenu"] = V;
+    }
+
+    get oncuechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oncuechange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oncuechange"]);
+    }
+
+    set oncuechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oncuechange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oncuechange' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oncuechange"] = V;
+    }
+
+    get ondblclick() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondblclick' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondblclick"]);
+    }
+
+    set ondblclick(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondblclick' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondblclick' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondblclick"] = V;
+    }
+
+    get ondrag() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondrag' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondrag"]);
+    }
+
+    set ondrag(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondrag' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondrag' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondrag"] = V;
+    }
+
+    get ondragend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragend' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragend"]);
+    }
+
+    set ondragend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragend' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragend' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragend"] = V;
+    }
+
+    get ondragenter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragenter' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragenter"]);
+    }
+
+    set ondragenter(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragenter' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragenter' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragenter"] = V;
+    }
+
+    get ondragleave() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragleave' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragleave"]);
+    }
+
+    set ondragleave(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragleave' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragleave' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragleave"] = V;
+    }
+
+    get ondragover() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragover' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragover"]);
+    }
+
+    set ondragover(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragover' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragover' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragover"] = V;
+    }
+
+    get ondragstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondragstart' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondragstart"]);
+    }
+
+    set ondragstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondragstart' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondragstart' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondragstart"] = V;
+    }
+
+    get ondrop() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondrop' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondrop"]);
+    }
+
+    set ondrop(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondrop' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondrop' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondrop"] = V;
+    }
+
+    get ondurationchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ondurationchange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ondurationchange"]);
+    }
+
+    set ondurationchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ondurationchange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ondurationchange' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ondurationchange"] = V;
+    }
+
+    get onemptied() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onemptied' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onemptied"]);
+    }
+
+    set onemptied(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onemptied' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onemptied' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onemptied"] = V;
+    }
+
+    get onended() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onended' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onended"]);
+    }
+
+    set onended(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onended' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onended' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onended"] = V;
+    }
+
+    get onerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onerror' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onerror"]);
+    }
+
+    set onerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onerror' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnErrorEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onerror"] = V;
+    }
+
+    get onfocus() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onfocus' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onfocus"]);
+    }
+
+    set onfocus(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onfocus' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onfocus' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onfocus"] = V;
+    }
+
+    get oninput() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oninput' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oninput"]);
+    }
+
+    set oninput(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oninput' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oninput' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oninput"] = V;
+    }
+
+    get oninvalid() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oninvalid' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["oninvalid"]);
+    }
+
+    set oninvalid(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set oninvalid' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'oninvalid' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["oninvalid"] = V;
+    }
+
+    get onkeydown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeydown' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeydown"]);
+    }
+
+    set onkeydown(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeydown' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeydown' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeydown"] = V;
+    }
+
+    get onkeypress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeypress' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeypress"]);
+    }
+
+    set onkeypress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeypress' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeypress' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeypress"] = V;
+    }
+
+    get onkeyup() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onkeyup' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onkeyup"]);
+    }
+
+    set onkeyup(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onkeyup' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onkeyup' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onkeyup"] = V;
+    }
+
+    get onload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onload' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onload"]);
+    }
+
+    set onload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onload' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onload' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onload"] = V;
+    }
+
+    get onloadeddata() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadeddata' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadeddata"]);
+    }
+
+    set onloadeddata(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadeddata' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadeddata' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadeddata"] = V;
+    }
+
+    get onloadedmetadata() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadedmetadata' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadedmetadata"]);
+    }
+
+    set onloadedmetadata(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadedmetadata' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadedmetadata' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadedmetadata"] = V;
+    }
+
+    get onloadend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadend' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadend"]);
+    }
+
+    set onloadend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadend' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadend' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadend"] = V;
+    }
+
+    get onloadstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onloadstart' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadstart"]);
+    }
+
+    set onloadstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onloadstart' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadstart' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadstart"] = V;
+    }
+
+    get onmousedown() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmousedown' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmousedown"]);
+    }
+
+    set onmousedown(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmousedown' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmousedown' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmousedown"] = V;
+    }
+
+    get onmouseenter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseenter"]);
+    }
+
+    set onmouseenter(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseenter' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseenter"] = V;
+    }
+
+    get onmouseleave() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseleave"]);
+    }
+
+    set onmouseleave(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        return;
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseleave' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseleave"] = V;
+    }
+
+    get onmousemove() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmousemove' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmousemove"]);
+    }
+
+    set onmousemove(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmousemove' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmousemove' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmousemove"] = V;
+    }
+
+    get onmouseout() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseout' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseout"]);
+    }
+
+    set onmouseout(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseout' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseout' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseout"] = V;
+    }
+
+    get onmouseover() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseover' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseover"]);
+    }
+
+    set onmouseover(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseover' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseover' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseover"] = V;
+    }
+
+    get onmouseup() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmouseup' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmouseup"]);
+    }
+
+    set onmouseup(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmouseup' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmouseup' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmouseup"] = V;
+    }
+
+    get onwheel() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onwheel' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onwheel"]);
+    }
+
+    set onwheel(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onwheel' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onwheel' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onwheel"] = V;
+    }
+
+    get onpause() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpause' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpause"]);
+    }
+
+    set onpause(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpause' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpause' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpause"] = V;
+    }
+
+    get onplay() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onplay' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onplay"]);
+    }
+
+    set onplay(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onplay' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onplay' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onplay"] = V;
+    }
+
+    get onplaying() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onplaying' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onplaying"]);
+    }
+
+    set onplaying(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onplaying' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onplaying' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onplaying"] = V;
+    }
+
+    get onprogress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onprogress' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onprogress"]);
+    }
+
+    set onprogress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onprogress' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onprogress' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onprogress"] = V;
+    }
+
+    get onratechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onratechange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onratechange"]);
+    }
+
+    set onratechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onratechange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onratechange' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onratechange"] = V;
+    }
+
+    get onreset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onreset' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onreset"]);
+    }
+
+    set onreset(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onreset' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onreset' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onreset"] = V;
+    }
+
+    get onresize() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onresize' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onresize"]);
+    }
+
+    set onresize(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onresize' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onresize' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onresize"] = V;
+    }
+
+    get onscroll() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onscroll' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onscroll"]);
+    }
+
+    set onscroll(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onscroll' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onscroll' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onscroll"] = V;
+    }
+
+    get onsecuritypolicyviolation() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onsecuritypolicyviolation' called on an object that is not a valid instance of SVGElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsecuritypolicyviolation"]);
+    }
+
+    set onsecuritypolicyviolation(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onsecuritypolicyviolation' called on an object that is not a valid instance of SVGElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsecuritypolicyviolation' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsecuritypolicyviolation"] = V;
+    }
+
+    get onseeked() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onseeked' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onseeked"]);
+    }
+
+    set onseeked(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onseeked' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onseeked' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onseeked"] = V;
+    }
+
+    get onseeking() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onseeking' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onseeking"]);
+    }
+
+    set onseeking(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onseeking' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onseeking' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onseeking"] = V;
+    }
+
+    get onselect() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onselect' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onselect"]);
+    }
+
+    set onselect(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onselect' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onselect' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onselect"] = V;
+    }
+
+    get onstalled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onstalled' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onstalled"]);
+    }
+
+    set onstalled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onstalled' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onstalled' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onstalled"] = V;
+    }
+
+    get onsubmit() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onsubmit' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsubmit"]);
+    }
+
+    set onsubmit(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onsubmit' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsubmit' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsubmit"] = V;
+    }
+
+    get onsuspend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onsuspend' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onsuspend"]);
+    }
+
+    set onsuspend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onsuspend' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onsuspend' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onsuspend"] = V;
+    }
+
+    get ontimeupdate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ontimeupdate' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontimeupdate"]);
+    }
+
+    set ontimeupdate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ontimeupdate' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontimeupdate' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontimeupdate"] = V;
+    }
+
+    get ontoggle() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ontoggle' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontoggle"]);
+    }
+
+    set ontoggle(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ontoggle' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontoggle' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontoggle"] = V;
+    }
+
+    get onvolumechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onvolumechange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onvolumechange"]);
+    }
+
+    set onvolumechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onvolumechange' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onvolumechange' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onvolumechange"] = V;
+    }
+
+    get onwaiting() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onwaiting' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onwaiting"]);
+    }
+
+    set onwaiting(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onwaiting' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onwaiting' property on 'SVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onwaiting"] = V;
+    }
+
+    get dataset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get dataset' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      return utils.getSameObject(this, "dataset", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["dataset"]);
+      });
+    }
+
+    get nonce() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get nonce' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      const value = esValue[implSymbol].getAttributeNS(null, "nonce");
+      return value === null ? "" : value;
+    }
+
+    set nonce(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set nonce' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'nonce' property on 'SVGElement': The provided value"
+      });
+
+      esValue[implSymbol].setAttributeNS(null, "nonce", V);
+    }
+
+    get tabIndex() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tabIndex' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["tabIndex"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set tabIndex(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set tabIndex' called on an object that is not a valid instance of SVGElement.");
+      }
+
+      V = conversions["long"](V, {
+        context: "Failed to set the 'tabIndex' property on 'SVGElement': The provided value"
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["tabIndex"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+  }
+  Object.defineProperties(SVGElement.prototype, {
+    focus: { enumerable: true },
+    blur: { enumerable: true },
+    className: { enumerable: true },
+    ownerSVGElement: { enumerable: true },
+    viewportElement: { enumerable: true },
+    style: { enumerable: true },
+    onabort: { enumerable: true },
+    onauxclick: { enumerable: true },
+    onblur: { enumerable: true },
+    oncancel: { enumerable: true },
+    oncanplay: { enumerable: true },
+    oncanplaythrough: { enumerable: true },
+    onchange: { enumerable: true },
+    onclick: { enumerable: true },
+    onclose: { enumerable: true },
+    oncontextmenu: { enumerable: true },
+    oncuechange: { enumerable: true },
+    ondblclick: { enumerable: true },
+    ondrag: { enumerable: true },
+    ondragend: { enumerable: true },
+    ondragenter: { enumerable: true },
+    ondragleave: { enumerable: true },
+    ondragover: { enumerable: true },
+    ondragstart: { enumerable: true },
+    ondrop: { enumerable: true },
+    ondurationchange: { enumerable: true },
+    onemptied: { enumerable: true },
+    onended: { enumerable: true },
+    onerror: { enumerable: true },
+    onfocus: { enumerable: true },
+    oninput: { enumerable: true },
+    oninvalid: { enumerable: true },
+    onkeydown: { enumerable: true },
+    onkeypress: { enumerable: true },
+    onkeyup: { enumerable: true },
+    onload: { enumerable: true },
+    onloadeddata: { enumerable: true },
+    onloadedmetadata: { enumerable: true },
+    onloadend: { enumerable: true },
+    onloadstart: { enumerable: true },
+    onmousedown: { enumerable: true },
+    onmouseenter: { enumerable: true },
+    onmouseleave: { enumerable: true },
+    onmousemove: { enumerable: true },
+    onmouseout: { enumerable: true },
+    onmouseover: { enumerable: true },
+    onmouseup: { enumerable: true },
+    onwheel: { enumerable: true },
+    onpause: { enumerable: true },
+    onplay: { enumerable: true },
+    onplaying: { enumerable: true },
+    onprogress: { enumerable: true },
+    onratechange: { enumerable: true },
+    onreset: { enumerable: true },
+    onresize: { enumerable: true },
+    onscroll: { enumerable: true },
+    onsecuritypolicyviolation: { enumerable: true },
+    onseeked: { enumerable: true },
+    onseeking: { enumerable: true },
+    onselect: { enumerable: true },
+    onstalled: { enumerable: true },
+    onsubmit: { enumerable: true },
+    onsuspend: { enumerable: true },
+    ontimeupdate: { enumerable: true },
+    ontoggle: { enumerable: true },
+    onvolumechange: { enumerable: true },
+    onwaiting: { enumerable: true },
+    dataset: { enumerable: true },
+    nonce: { enumerable: true },
+    tabIndex: { enumerable: true },
+    [Symbol.toStringTag]: { value: "SVGElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGElement
+  });
+};
+
+const Impl = require("../nodes/SVGElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGGraphicsElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGGraphicsElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGGraphicsElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,144 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const SVGElement = require("./SVGElement.js");
+
+const interfaceName = "SVGGraphicsElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGGraphicsElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGGraphicsElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGGraphicsElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  SVGElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.SVGElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate SVGGraphicsElement before SVGElement");
+  }
+  class SVGGraphicsElement extends globalObject.SVGElement {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get requiredExtensions() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get requiredExtensions' called on an object that is not a valid instance of SVGGraphicsElement."
+        );
+      }
+
+      return utils.getSameObject(this, "requiredExtensions", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["requiredExtensions"]);
+      });
+    }
+
+    get systemLanguage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get systemLanguage' called on an object that is not a valid instance of SVGGraphicsElement."
+        );
+      }
+
+      return utils.getSameObject(this, "systemLanguage", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["systemLanguage"]);
+      });
+    }
+  }
+  Object.defineProperties(SVGGraphicsElement.prototype, {
+    requiredExtensions: { enumerable: true },
+    systemLanguage: { enumerable: true },
+    [Symbol.toStringTag]: { value: "SVGGraphicsElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGGraphicsElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGGraphicsElement
+  });
+};
+
+const Impl = require("../nodes/SVGGraphicsElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGNumber.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGNumber.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGNumber.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,130 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "SVGNumber";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGNumber'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGNumber"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGNumber is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class SVGNumber {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get value() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get value' called on an object that is not a valid instance of SVGNumber.");
+      }
+
+      return esValue[implSymbol]["value"];
+    }
+
+    set value(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set value' called on an object that is not a valid instance of SVGNumber.");
+      }
+
+      V = conversions["float"](V, { context: "Failed to set the 'value' property on 'SVGNumber': The provided value" });
+
+      esValue[implSymbol]["value"] = V;
+    }
+  }
+  Object.defineProperties(SVGNumber.prototype, {
+    value: { enumerable: true },
+    [Symbol.toStringTag]: { value: "SVGNumber", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGNumber;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGNumber
+  });
+};
+
+const Impl = require("../svg/SVGNumber-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGSVGElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGSVGElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGSVGElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,681 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const OnBeforeUnloadEventHandlerNonNull = require("./OnBeforeUnloadEventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const SVGGraphicsElement = require("./SVGGraphicsElement.js");
+
+const interfaceName = "SVGSVGElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGSVGElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGSVGElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGSVGElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  SVGGraphicsElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.SVGGraphicsElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate SVGSVGElement before SVGGraphicsElement");
+  }
+  class SVGSVGElement extends globalObject.SVGGraphicsElement {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    createSVGNumber() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'createSVGNumber' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].createSVGNumber());
+    }
+
+    getElementById(elementId) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getElementById' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getElementById' on 'SVGSVGElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'getElementById' on 'SVGSVGElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getElementById(...args));
+    }
+
+    suspendRedraw(maxWaitMilliseconds) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'suspendRedraw' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'suspendRedraw' on 'SVGSVGElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'suspendRedraw' on 'SVGSVGElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].suspendRedraw(...args);
+    }
+
+    unsuspendRedraw(suspendHandleID) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'unsuspendRedraw' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'unsuspendRedraw' on 'SVGSVGElement': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'unsuspendRedraw' on 'SVGSVGElement': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].unsuspendRedraw(...args);
+    }
+
+    unsuspendRedrawAll() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'unsuspendRedrawAll' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return esValue[implSymbol].unsuspendRedrawAll();
+    }
+
+    forceRedraw() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'forceRedraw' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return esValue[implSymbol].forceRedraw();
+    }
+
+    get onafterprint() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onafterprint' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onafterprint"]);
+    }
+
+    set onafterprint(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onafterprint' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onafterprint' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onafterprint"] = V;
+    }
+
+    get onbeforeprint() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onbeforeprint' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onbeforeprint"]);
+    }
+
+    set onbeforeprint(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onbeforeprint' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeprint' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onbeforeprint"] = V;
+    }
+
+    get onbeforeunload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onbeforeunload' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onbeforeunload"]);
+    }
+
+    set onbeforeunload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onbeforeunload' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = OnBeforeUnloadEventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onbeforeunload' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onbeforeunload"] = V;
+    }
+
+    get onhashchange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onhashchange' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onhashchange"]);
+    }
+
+    set onhashchange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onhashchange' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onhashchange' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onhashchange"] = V;
+    }
+
+    get onlanguagechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onlanguagechange' called on an object that is not a valid instance of SVGSVGElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onlanguagechange"]);
+    }
+
+    set onlanguagechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onlanguagechange' called on an object that is not a valid instance of SVGSVGElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onlanguagechange' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onlanguagechange"] = V;
+    }
+
+    get onmessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmessage' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessage"]);
+    }
+
+    set onmessage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmessage' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessage' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessage"] = V;
+    }
+
+    get onmessageerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmessageerror' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessageerror"]);
+    }
+
+    set onmessageerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmessageerror' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessageerror' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessageerror"] = V;
+    }
+
+    get onoffline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onoffline' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onoffline"]);
+    }
+
+    set onoffline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onoffline' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onoffline' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onoffline"] = V;
+    }
+
+    get ononline() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ononline' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ononline"]);
+    }
+
+    set ononline(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set ononline' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ononline' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["ononline"] = V;
+    }
+
+    get onpagehide() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpagehide' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpagehide"]);
+    }
+
+    set onpagehide(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpagehide' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpagehide' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpagehide"] = V;
+    }
+
+    get onpageshow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpageshow' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpageshow"]);
+    }
+
+    set onpageshow(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpageshow' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpageshow' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpageshow"] = V;
+    }
+
+    get onpopstate() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onpopstate' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onpopstate"]);
+    }
+
+    set onpopstate(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onpopstate' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onpopstate' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onpopstate"] = V;
+    }
+
+    get onrejectionhandled() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onrejectionhandled' called on an object that is not a valid instance of SVGSVGElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onrejectionhandled"]);
+    }
+
+    set onrejectionhandled(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onrejectionhandled' called on an object that is not a valid instance of SVGSVGElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onrejectionhandled' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onrejectionhandled"] = V;
+    }
+
+    get onstorage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onstorage' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onstorage"]);
+    }
+
+    set onstorage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onstorage' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onstorage' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onstorage"] = V;
+    }
+
+    get onunhandledrejection() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onunhandledrejection' called on an object that is not a valid instance of SVGSVGElement."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onunhandledrejection"]);
+    }
+
+    set onunhandledrejection(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onunhandledrejection' called on an object that is not a valid instance of SVGSVGElement."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onunhandledrejection' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onunhandledrejection"] = V;
+    }
+
+    get onunload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onunload' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onunload"]);
+    }
+
+    set onunload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onunload' called on an object that is not a valid instance of SVGSVGElement.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onunload' property on 'SVGSVGElement': The provided value"
+        });
+      }
+      esValue[implSymbol]["onunload"] = V;
+    }
+  }
+  Object.defineProperties(SVGSVGElement.prototype, {
+    createSVGNumber: { enumerable: true },
+    getElementById: { enumerable: true },
+    suspendRedraw: { enumerable: true },
+    unsuspendRedraw: { enumerable: true },
+    unsuspendRedrawAll: { enumerable: true },
+    forceRedraw: { enumerable: true },
+    onafterprint: { enumerable: true },
+    onbeforeprint: { enumerable: true },
+    onbeforeunload: { enumerable: true },
+    onhashchange: { enumerable: true },
+    onlanguagechange: { enumerable: true },
+    onmessage: { enumerable: true },
+    onmessageerror: { enumerable: true },
+    onoffline: { enumerable: true },
+    ononline: { enumerable: true },
+    onpagehide: { enumerable: true },
+    onpageshow: { enumerable: true },
+    onpopstate: { enumerable: true },
+    onrejectionhandled: { enumerable: true },
+    onstorage: { enumerable: true },
+    onunhandledrejection: { enumerable: true },
+    onunload: { enumerable: true },
+    [Symbol.toStringTag]: { value: "SVGSVGElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGSVGElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGSVGElement
+  });
+};
+
+const Impl = require("../nodes/SVGSVGElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGStringList.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGStringList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGStringList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,504 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "SVGStringList";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGStringList'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGStringList"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGStringList is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class SVGStringList {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    clear() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'clear' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      return esValue[implSymbol].clear();
+    }
+
+    initialize(newItem) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initialize' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initialize' on 'SVGStringList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initialize' on 'SVGStringList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initialize(...args);
+    }
+
+    getItem(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getItem' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getItem' on 'SVGStringList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'getItem' on 'SVGStringList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getItem(...args);
+    }
+
+    insertItemBefore(newItem, index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'insertItemBefore' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'insertItemBefore' on 'SVGStringList': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'insertItemBefore' on 'SVGStringList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'insertItemBefore' on 'SVGStringList': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].insertItemBefore(...args);
+    }
+
+    replaceItem(newItem, index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'replaceItem' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'replaceItem' on 'SVGStringList': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'replaceItem' on 'SVGStringList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'replaceItem' on 'SVGStringList': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].replaceItem(...args);
+    }
+
+    removeItem(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeItem' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeItem' on 'SVGStringList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'removeItem' on 'SVGStringList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].removeItem(...args);
+    }
+
+    appendItem(newItem) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'appendItem' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'appendItem' on 'SVGStringList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'appendItem' on 'SVGStringList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].appendItem(...args);
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+
+    get numberOfItems() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get numberOfItems' called on an object that is not a valid instance of SVGStringList.");
+      }
+
+      return esValue[implSymbol]["numberOfItems"];
+    }
+  }
+  Object.defineProperties(SVGStringList.prototype, {
+    clear: { enumerable: true },
+    initialize: { enumerable: true },
+    getItem: { enumerable: true },
+    insertItemBefore: { enumerable: true },
+    replaceItem: { enumerable: true },
+    removeItem: { enumerable: true },
+    appendItem: { enumerable: true },
+    length: { enumerable: true },
+    numberOfItems: { enumerable: true },
+    [Symbol.toStringTag]: { value: "SVGStringList", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGStringList;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGStringList
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+
+      if (target[implSymbol][utils.supportsPropertyIndex](index)) {
+        const indexedValue = target[implSymbol].getItem(index);
+        return {
+          writable: true,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+      if (utils.isArrayIndexPropName(P)) {
+        const index = P >>> 0;
+        let indexedValue = V;
+
+        indexedValue = conversions["DOMString"](indexedValue, {
+          context: "Failed to set the " + index + " property on 'SVGStringList': The provided value"
+        });
+
+        const creating = !target[implSymbol][utils.supportsPropertyIndex](index);
+        if (creating) {
+          target[implSymbol][utils.indexedSetNew](index, indexedValue);
+        } else {
+          target[implSymbol][utils.indexedSetExisting](index, indexedValue);
+        }
+
+        return true;
+      }
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+
+      if (target[implSymbol][utils.supportsPropertyIndex](index)) {
+        const indexedValue = target[implSymbol].getItem(index);
+        ownDesc = {
+          writable: true,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      if (desc.get || desc.set) {
+        return false;
+      }
+
+      const index = P >>> 0;
+      let indexedValue = desc.value;
+
+      indexedValue = conversions["DOMString"](indexedValue, {
+        context: "Failed to set the " + index + " property on 'SVGStringList': The provided value"
+      });
+
+      const creating = !target[implSymbol][utils.supportsPropertyIndex](index);
+      if (creating) {
+        target[implSymbol][utils.indexedSetNew](index, indexedValue);
+      } else {
+        target[implSymbol][utils.indexedSetExisting](index, indexedValue);
+      }
+
+      return true;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !target[implSymbol][utils.supportsPropertyIndex](index);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../svg/SVGStringList-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGTitleElement.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGTitleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SVGTitleElement.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const SVGElement = require("./SVGElement.js");
+
+const interfaceName = "SVGTitleElement";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'SVGTitleElement'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["SVGTitleElement"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor SVGTitleElement is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  SVGElement._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.SVGElement === undefined) {
+    throw new Error("Internal error: attempting to evaluate SVGTitleElement before SVGElement");
+  }
+  class SVGTitleElement extends globalObject.SVGElement {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(SVGTitleElement.prototype, {
+    [Symbol.toStringTag]: { value: "SVGTitleElement", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = SVGTitleElement;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: SVGTitleElement
+  });
+};
+
+const Impl = require("../nodes/SVGTitleElement-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Screen.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Screen.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Screen.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,173 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Screen";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Screen'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Screen"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Screen is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Screen {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get availWidth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get availWidth' called on an object that is not a valid instance of Screen.");
+      }
+
+      return esValue[implSymbol]["availWidth"];
+    }
+
+    get availHeight() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get availHeight' called on an object that is not a valid instance of Screen.");
+      }
+
+      return esValue[implSymbol]["availHeight"];
+    }
+
+    get width() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get width' called on an object that is not a valid instance of Screen.");
+      }
+
+      return esValue[implSymbol]["width"];
+    }
+
+    get height() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get height' called on an object that is not a valid instance of Screen.");
+      }
+
+      return esValue[implSymbol]["height"];
+    }
+
+    get colorDepth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get colorDepth' called on an object that is not a valid instance of Screen.");
+      }
+
+      return esValue[implSymbol]["colorDepth"];
+    }
+
+    get pixelDepth() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get pixelDepth' called on an object that is not a valid instance of Screen.");
+      }
+
+      return esValue[implSymbol]["pixelDepth"];
+    }
+  }
+  Object.defineProperties(Screen.prototype, {
+    availWidth: { enumerable: true },
+    availHeight: { enumerable: true },
+    width: { enumerable: true },
+    height: { enumerable: true },
+    colorDepth: { enumerable: true },
+    pixelDepth: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Screen", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Screen;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Screen
+  });
+};
+
+const Impl = require("../window/Screen-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollBehavior.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollBehavior.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollBehavior.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["auto", "instant", "smooth"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for ScrollBehavior`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollIntoViewOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollIntoViewOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollIntoViewOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,45 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ScrollLogicalPosition = require("./ScrollLogicalPosition.js");
+const ScrollOptions = require("./ScrollOptions.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  ScrollOptions._convertInherit(obj, ret, { context });
+
+  {
+    const key = "block";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = ScrollLogicalPosition.convert(value, { context: context + " has member 'block' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "start";
+    }
+  }
+
+  {
+    const key = "inline";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = ScrollLogicalPosition.convert(value, { context: context + " has member 'inline' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "nearest";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollLogicalPosition.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollLogicalPosition.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollLogicalPosition.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["start", "center", "end", "nearest"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for ScrollLogicalPosition`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollOptions.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollOptions.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ScrollBehavior = require("./ScrollBehavior.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "behavior";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = ScrollBehavior.convert(value, { context: context + " has member 'behavior' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "auto";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollRestoration.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollRestoration.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ScrollRestoration.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["auto", "manual"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for ScrollRestoration`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Selection.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Selection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Selection.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,527 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Range = require("./Range.js");
+const Node = require("./Node.js");
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Selection";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Selection'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Selection"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Selection is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Selection {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    getRangeAt(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getRangeAt' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getRangeAt' on 'Selection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'getRangeAt' on 'Selection': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].getRangeAt(...args));
+    }
+
+    addRange(range) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'addRange' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'addRange' on 'Selection': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Range.convert(curArg, { context: "Failed to execute 'addRange' on 'Selection': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].addRange(...args);
+    }
+
+    removeRange(range) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeRange' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeRange' on 'Selection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Range.convert(curArg, { context: "Failed to execute 'removeRange' on 'Selection': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].removeRange(...args);
+    }
+
+    removeAllRanges() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeAllRanges' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol].removeAllRanges();
+    }
+
+    empty() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'empty' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol].empty();
+    }
+
+    collapse(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'collapse' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'collapse' on 'Selection': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = Node.convert(curArg, { context: "Failed to execute 'collapse' on 'Selection': parameter 1" });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned long"](curArg, {
+            context: "Failed to execute 'collapse' on 'Selection': parameter 2"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].collapse(...args);
+    }
+
+    setPosition(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setPosition' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'setPosition' on 'Selection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg === null || curArg === undefined) {
+          curArg = null;
+        } else {
+          curArg = Node.convert(curArg, { context: "Failed to execute 'setPosition' on 'Selection': parameter 1" });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned long"](curArg, {
+            context: "Failed to execute 'setPosition' on 'Selection': parameter 2"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setPosition(...args);
+    }
+
+    collapseToStart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'collapseToStart' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol].collapseToStart();
+    }
+
+    collapseToEnd() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'collapseToEnd' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol].collapseToEnd();
+    }
+
+    extend(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'extend' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'extend' on 'Selection': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'extend' on 'Selection': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned long"](curArg, {
+            context: "Failed to execute 'extend' on 'Selection': parameter 2"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].extend(...args);
+    }
+
+    setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setBaseAndExtent' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 4) {
+        throw new TypeError(
+          "Failed to execute 'setBaseAndExtent' on 'Selection': 4 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setBaseAndExtent' on 'Selection': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setBaseAndExtent' on 'Selection': parameter 2"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'setBaseAndExtent' on 'Selection': parameter 3" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'setBaseAndExtent' on 'Selection': parameter 4"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setBaseAndExtent(...args);
+    }
+
+    selectAllChildren(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'selectAllChildren' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'selectAllChildren' on 'Selection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'selectAllChildren' on 'Selection': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].selectAllChildren(...args);
+    }
+
+    deleteFromDocument() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'deleteFromDocument' called on an object that is not a valid instance of Selection.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol].deleteFromDocument();
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    containsNode(node) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'containsNode' called on an object that is not a valid instance of Selection.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'containsNode' on 'Selection': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, { context: "Failed to execute 'containsNode' on 'Selection': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'containsNode' on 'Selection': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].containsNode(...args);
+    }
+
+    toString() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'toString' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol].toString();
+    }
+
+    get anchorNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get anchorNode' called on an object that is not a valid instance of Selection.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["anchorNode"]);
+    }
+
+    get anchorOffset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get anchorOffset' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol]["anchorOffset"];
+    }
+
+    get focusNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get focusNode' called on an object that is not a valid instance of Selection.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["focusNode"]);
+    }
+
+    get focusOffset() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get focusOffset' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol]["focusOffset"];
+    }
+
+    get isCollapsed() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get isCollapsed' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol]["isCollapsed"];
+    }
+
+    get rangeCount() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rangeCount' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol]["rangeCount"];
+    }
+
+    get type() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get type' called on an object that is not a valid instance of Selection.");
+      }
+
+      return esValue[implSymbol]["type"];
+    }
+  }
+  Object.defineProperties(Selection.prototype, {
+    getRangeAt: { enumerable: true },
+    addRange: { enumerable: true },
+    removeRange: { enumerable: true },
+    removeAllRanges: { enumerable: true },
+    empty: { enumerable: true },
+    collapse: { enumerable: true },
+    setPosition: { enumerable: true },
+    collapseToStart: { enumerable: true },
+    collapseToEnd: { enumerable: true },
+    extend: { enumerable: true },
+    setBaseAndExtent: { enumerable: true },
+    selectAllChildren: { enumerable: true },
+    deleteFromDocument: { enumerable: true },
+    containsNode: { enumerable: true },
+    toString: { enumerable: true },
+    anchorNode: { enumerable: true },
+    anchorOffset: { enumerable: true },
+    focusNode: { enumerable: true },
+    focusOffset: { enumerable: true },
+    isCollapsed: { enumerable: true },
+    rangeCount: { enumerable: true },
+    type: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Selection", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Selection;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Selection
+  });
+};
+
+const Impl = require("../selection/Selection-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SelectionMode.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SelectionMode.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SelectionMode.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["select", "start", "end", "preserve"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for SelectionMode`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRoot.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRoot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRoot.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,185 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ceReactionsPreSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPreSteps;
+const ceReactionsPostSteps_helpers_custom_elements = require("../helpers/custom-elements.js").ceReactionsPostSteps;
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const DocumentFragment = require("./DocumentFragment.js");
+
+const interfaceName = "ShadowRoot";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'ShadowRoot'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["ShadowRoot"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor ShadowRoot is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  DocumentFragment._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.DocumentFragment === undefined) {
+    throw new Error("Internal error: attempting to evaluate ShadowRoot before DocumentFragment");
+  }
+  class ShadowRoot extends globalObject.DocumentFragment {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get mode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get mode' called on an object that is not a valid instance of ShadowRoot.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["mode"]);
+    }
+
+    get host() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get host' called on an object that is not a valid instance of ShadowRoot.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["host"]);
+    }
+
+    get innerHTML() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get innerHTML' called on an object that is not a valid instance of ShadowRoot.");
+      }
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        return esValue[implSymbol]["innerHTML"];
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    set innerHTML(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set innerHTML' called on an object that is not a valid instance of ShadowRoot.");
+      }
+
+      V = conversions["DOMString"](V, {
+        context: "Failed to set the 'innerHTML' property on 'ShadowRoot': The provided value",
+        treatNullAsEmptyString: true
+      });
+
+      ceReactionsPreSteps_helpers_custom_elements(globalObject);
+      try {
+        esValue[implSymbol]["innerHTML"] = V;
+      } finally {
+        ceReactionsPostSteps_helpers_custom_elements(globalObject);
+      }
+    }
+
+    get activeElement() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get activeElement' called on an object that is not a valid instance of ShadowRoot.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["activeElement"]);
+    }
+  }
+  Object.defineProperties(ShadowRoot.prototype, {
+    mode: { enumerable: true },
+    host: { enumerable: true },
+    innerHTML: { enumerable: true },
+    activeElement: { enumerable: true },
+    [Symbol.toStringTag]: { value: "ShadowRoot", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = ShadowRoot;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: ShadowRoot
+  });
+};
+
+const Impl = require("../nodes/ShadowRoot-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRootInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRootInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRootInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const ShadowRootMode = require("./ShadowRootMode.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "mode";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = ShadowRootMode.convert(value, { context: context + " has member 'mode' that" });
+
+      ret[key] = value;
+    } else {
+      throw new TypeError("mode is required in 'ShadowRootInit'");
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRootMode.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRootMode.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ShadowRootMode.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["open", "closed"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for ShadowRootMode`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/StaticRange.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/StaticRange.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/StaticRange.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,126 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const StaticRangeInit = require("./StaticRangeInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const AbstractRange = require("./AbstractRange.js");
+
+const interfaceName = "StaticRange";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'StaticRange'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["StaticRange"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor StaticRange is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  AbstractRange._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.AbstractRange === undefined) {
+    throw new Error("Internal error: attempting to evaluate StaticRange before AbstractRange");
+  }
+  class StaticRange extends globalObject.AbstractRange {
+    constructor(init) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'StaticRange': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = StaticRangeInit.convert(curArg, { context: "Failed to construct 'StaticRange': parameter 1" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+  }
+  Object.defineProperties(StaticRange.prototype, {
+    [Symbol.toStringTag]: { value: "StaticRange", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = StaticRange;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: StaticRange
+  });
+};
+
+const Impl = require("../range/StaticRange-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/StaticRangeInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/StaticRangeInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/StaticRangeInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,66 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  {
+    const key = "endContainer";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = Node.convert(value, { context: context + " has member 'endContainer' that" });
+
+      ret[key] = value;
+    } else {
+      throw new TypeError("endContainer is required in 'StaticRangeInit'");
+    }
+  }
+
+  {
+    const key = "endOffset";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'endOffset' that" });
+
+      ret[key] = value;
+    } else {
+      throw new TypeError("endOffset is required in 'StaticRangeInit'");
+    }
+  }
+
+  {
+    const key = "startContainer";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = Node.convert(value, { context: context + " has member 'startContainer' that" });
+
+      ret[key] = value;
+    } else {
+      throw new TypeError("startContainer is required in 'StaticRangeInit'");
+    }
+  }
+
+  {
+    const key = "startOffset";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'startOffset' that" });
+
+      ret[key] = value;
+    } else {
+      throw new TypeError("startOffset is required in 'StaticRangeInit'");
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Storage.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Storage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Storage.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,389 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "Storage";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Storage'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Storage"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Storage is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class Storage {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    key(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'key' called on an object that is not a valid instance of Storage.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'key' on 'Storage': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, { context: "Failed to execute 'key' on 'Storage': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].key(...args);
+    }
+
+    getItem(key) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getItem' called on an object that is not a valid instance of Storage.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getItem' on 'Storage': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'getItem' on 'Storage': parameter 1" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getItem(...args);
+    }
+
+    setItem(key, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setItem' called on an object that is not a valid instance of Storage.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setItem' on 'Storage': 2 arguments required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'setItem' on 'Storage': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'setItem' on 'Storage': parameter 2" });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setItem(...args);
+    }
+
+    removeItem(key) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'removeItem' called on an object that is not a valid instance of Storage.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'removeItem' on 'Storage': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'removeItem' on 'Storage': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].removeItem(...args);
+    }
+
+    clear() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'clear' called on an object that is not a valid instance of Storage.");
+      }
+
+      return esValue[implSymbol].clear();
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of Storage.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(Storage.prototype, {
+    key: { enumerable: true },
+    getItem: { enumerable: true },
+    setItem: { enumerable: true },
+    removeItem: { enumerable: true },
+    clear: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Storage", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Storage;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Storage
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyNames]) {
+      if (!(key in target)) {
+        keys.add(`${key}`);
+      }
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    const namedValue = target[implSymbol].getItem(P);
+
+    if (namedValue !== null && !(P in target) && !ignoreNamedProps) {
+      return {
+        writable: true,
+        enumerable: true,
+        configurable: true,
+        value: utils.tryWrapperForImpl(namedValue)
+      };
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+      if (typeof P === "string") {
+        let namedValue = V;
+
+        namedValue = conversions["DOMString"](namedValue, {
+          context: "Failed to set the '" + P + "' property on 'Storage': The provided value"
+        });
+
+        target[implSymbol].setItem(P, namedValue);
+
+        return true;
+      }
+    }
+    let ownDesc;
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+    if (!utils.hasOwn(target, P)) {
+      if (desc.get || desc.set) {
+        return false;
+      }
+
+      let namedValue = desc.value;
+
+      namedValue = conversions["DOMString"](namedValue, {
+        context: "Failed to set the '" + P + "' property on 'Storage': The provided value"
+      });
+
+      target[implSymbol].setItem(P, namedValue);
+
+      return true;
+    }
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (target[implSymbol].getItem(P) !== null && !(P in target)) {
+      target[implSymbol].removeItem(P);
+      return true;
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../webstorage/Storage-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/StorageEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/StorageEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/StorageEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,305 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const StorageEventInit = require("./StorageEventInit.js");
+const Storage = require("./Storage.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "StorageEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'StorageEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["StorageEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor StorageEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate StorageEvent before Event");
+  }
+  class StorageEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'StorageEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'StorageEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = StorageEventInit.convert(curArg, { context: "Failed to construct 'StorageEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    initStorageEvent(type) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initStorageEvent' called on an object that is not a valid instance of StorageEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initStorageEvent' on 'StorageEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 4"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[4];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 5"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[5];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = conversions["DOMString"](curArg, {
+              context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 6"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[6];
+        if (curArg !== undefined) {
+          curArg = conversions["USVString"](curArg, {
+            context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 7"
+          });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[7];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = Storage.convert(curArg, {
+              context: "Failed to execute 'initStorageEvent' on 'StorageEvent': parameter 8"
+            });
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initStorageEvent(...args);
+    }
+
+    get key() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get key' called on an object that is not a valid instance of StorageEvent.");
+      }
+
+      return esValue[implSymbol]["key"];
+    }
+
+    get oldValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get oldValue' called on an object that is not a valid instance of StorageEvent.");
+      }
+
+      return esValue[implSymbol]["oldValue"];
+    }
+
+    get newValue() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get newValue' called on an object that is not a valid instance of StorageEvent.");
+      }
+
+      return esValue[implSymbol]["newValue"];
+    }
+
+    get url() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get url' called on an object that is not a valid instance of StorageEvent.");
+      }
+
+      return esValue[implSymbol]["url"];
+    }
+
+    get storageArea() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get storageArea' called on an object that is not a valid instance of StorageEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["storageArea"]);
+    }
+  }
+  Object.defineProperties(StorageEvent.prototype, {
+    initStorageEvent: { enumerable: true },
+    key: { enumerable: true },
+    oldValue: { enumerable: true },
+    newValue: { enumerable: true },
+    url: { enumerable: true },
+    storageArea: { enumerable: true },
+    [Symbol.toStringTag]: { value: "StorageEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = StorageEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: StorageEvent
+  });
+};
+
+const Impl = require("../events/StorageEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/StorageEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/StorageEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/StorageEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,93 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Storage = require("./Storage.js");
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "key";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = conversions["DOMString"](value, { context: context + " has member 'key' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "newValue";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = conversions["DOMString"](value, { context: context + " has member 'newValue' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "oldValue";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = conversions["DOMString"](value, { context: context + " has member 'oldValue' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "storageArea";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = Storage.convert(value, { context: context + " has member 'storageArea' that" });
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "url";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["USVString"](value, { context: context + " has member 'url' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = "";
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/StyleSheetList.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/StyleSheetList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/StyleSheetList.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,307 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "StyleSheetList";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'StyleSheetList'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["StyleSheetList"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor StyleSheetList is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  let wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper = new Proxy(wrapper, proxyHandler);
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class StyleSheetList {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    item(index) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'item' called on an object that is not a valid instance of StyleSheetList.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'item' on 'StyleSheetList': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'item' on 'StyleSheetList': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].item(...args));
+    }
+
+    get length() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get length' called on an object that is not a valid instance of StyleSheetList.");
+      }
+
+      return esValue[implSymbol]["length"];
+    }
+  }
+  Object.defineProperties(StyleSheetList.prototype, {
+    item: { enumerable: true },
+    length: { enumerable: true },
+    [Symbol.toStringTag]: { value: "StyleSheetList", configurable: true },
+    [Symbol.iterator]: { value: Array.prototype[Symbol.iterator], configurable: true, writable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = StyleSheetList;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: StyleSheetList
+  });
+};
+
+const proxyHandler = {
+  get(target, P, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.get(target, P, receiver);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc === undefined) {
+      const parent = Object.getPrototypeOf(target);
+      if (parent === null) {
+        return undefined;
+      }
+      return Reflect.get(target, P, receiver);
+    }
+    if (!desc.get && !desc.set) {
+      return desc.value;
+    }
+    const getter = desc.get;
+    if (getter === undefined) {
+      return undefined;
+    }
+    return Reflect.apply(getter, receiver, []);
+  },
+
+  has(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.has(target, P);
+    }
+    const desc = this.getOwnPropertyDescriptor(target, P);
+    if (desc !== undefined) {
+      return true;
+    }
+    const parent = Object.getPrototypeOf(target);
+    if (parent !== null) {
+      return Reflect.has(parent, P);
+    }
+    return false;
+  },
+
+  ownKeys(target) {
+    const keys = new Set();
+
+    for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
+      keys.add(`${key}`);
+    }
+
+    for (const key of Reflect.ownKeys(target)) {
+      keys.add(key);
+    }
+    return [...keys];
+  },
+
+  getOwnPropertyDescriptor(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    let ignoreNamedProps = false;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        return {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+      ignoreNamedProps = true;
+    }
+
+    return Reflect.getOwnPropertyDescriptor(target, P);
+  },
+
+  set(target, P, V, receiver) {
+    if (typeof P === "symbol") {
+      return Reflect.set(target, P, V, receiver);
+    }
+    // The `receiver` argument refers to the Proxy exotic object or an object
+    // that inherits from it, whereas `target` refers to the Proxy target:
+    if (target[implSymbol][utils.wrapperSymbol] === receiver) {
+    }
+    let ownDesc;
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      const indexedValue = target[implSymbol].item(index);
+      if (indexedValue !== null) {
+        ownDesc = {
+          writable: false,
+          enumerable: true,
+          configurable: true,
+          value: utils.tryWrapperForImpl(indexedValue)
+        };
+      }
+    }
+
+    if (ownDesc === undefined) {
+      ownDesc = Reflect.getOwnPropertyDescriptor(target, P);
+    }
+    if (ownDesc === undefined) {
+      const parent = Reflect.getPrototypeOf(target);
+      if (parent !== null) {
+        return Reflect.set(parent, P, V, receiver);
+      }
+      ownDesc = { writable: true, enumerable: true, configurable: true, value: undefined };
+    }
+    if (!ownDesc.writable) {
+      return false;
+    }
+    if (!utils.isObject(receiver)) {
+      return false;
+    }
+    const existingDesc = Reflect.getOwnPropertyDescriptor(receiver, P);
+    let valueDesc;
+    if (existingDesc !== undefined) {
+      if (existingDesc.get || existingDesc.set) {
+        return false;
+      }
+      if (!existingDesc.writable) {
+        return false;
+      }
+      valueDesc = { value: V };
+    } else {
+      valueDesc = { writable: true, enumerable: true, configurable: true, value: V };
+    }
+    return Reflect.defineProperty(receiver, P, valueDesc);
+  },
+
+  defineProperty(target, P, desc) {
+    if (typeof P === "symbol") {
+      return Reflect.defineProperty(target, P, desc);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      return false;
+    }
+
+    return Reflect.defineProperty(target, P, desc);
+  },
+
+  deleteProperty(target, P) {
+    if (typeof P === "symbol") {
+      return Reflect.deleteProperty(target, P);
+    }
+
+    if (utils.isArrayIndexPropName(P)) {
+      const index = P >>> 0;
+      return !(target[implSymbol].item(index) !== null);
+    }
+
+    return Reflect.deleteProperty(target, P);
+  },
+
+  preventExtensions() {
+    return false;
+  }
+};
+
+const Impl = require("../cssom/StyleSheetList-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/SupportedType.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/SupportedType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/SupportedType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+"use strict";
+
+const enumerationValues = new Set([
+  "text/html",
+  "text/xml",
+  "application/xml",
+  "application/xhtml+xml",
+  "image/svg+xml"
+]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for SupportedType`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/Text.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/Text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/Text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,169 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const CharacterData = require("./CharacterData.js");
+
+const interfaceName = "Text";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'Text'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["Text"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor Text is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  CharacterData._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.CharacterData === undefined) {
+    throw new Error("Internal error: attempting to evaluate Text before CharacterData");
+  }
+  class Text extends globalObject.CharacterData {
+    constructor() {
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'Text': parameter 1" });
+        } else {
+          curArg = "";
+        }
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    splitText(offset) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'splitText' called on an object that is not a valid instance of Text.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'splitText' on 'Text': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["unsigned long"](curArg, {
+          context: "Failed to execute 'splitText' on 'Text': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return utils.tryWrapperForImpl(esValue[implSymbol].splitText(...args));
+    }
+
+    get wholeText() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get wholeText' called on an object that is not a valid instance of Text.");
+      }
+
+      return esValue[implSymbol]["wholeText"];
+    }
+
+    get assignedSlot() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get assignedSlot' called on an object that is not a valid instance of Text.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["assignedSlot"]);
+    }
+  }
+  Object.defineProperties(Text.prototype, {
+    splitText: { enumerable: true },
+    wholeText: { enumerable: true },
+    assignedSlot: { enumerable: true },
+    [Symbol.toStringTag]: { value: "Text", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = Text;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: Text
+  });
+};
+
+const Impl = require("../nodes/Text-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/TextTrackKind.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/TextTrackKind.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/TextTrackKind.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["subtitles", "captions", "descriptions", "chapters", "metadata"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for TextTrackKind`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/TouchEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/TouchEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/TouchEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,208 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const TouchEventInit = require("./TouchEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const UIEvent = require("./UIEvent.js");
+
+const interfaceName = "TouchEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'TouchEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["TouchEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor TouchEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  UIEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.UIEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate TouchEvent before UIEvent");
+  }
+  class TouchEvent extends globalObject.UIEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'TouchEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'TouchEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = TouchEventInit.convert(curArg, { context: "Failed to construct 'TouchEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get touches() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get touches' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["touches"]);
+    }
+
+    get targetTouches() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get targetTouches' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["targetTouches"]);
+    }
+
+    get changedTouches() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get changedTouches' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["changedTouches"]);
+    }
+
+    get altKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get altKey' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return esValue[implSymbol]["altKey"];
+    }
+
+    get metaKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get metaKey' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return esValue[implSymbol]["metaKey"];
+    }
+
+    get ctrlKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get ctrlKey' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return esValue[implSymbol]["ctrlKey"];
+    }
+
+    get shiftKey() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get shiftKey' called on an object that is not a valid instance of TouchEvent.");
+      }
+
+      return esValue[implSymbol]["shiftKey"];
+    }
+  }
+  Object.defineProperties(TouchEvent.prototype, {
+    touches: { enumerable: true },
+    targetTouches: { enumerable: true },
+    changedTouches: { enumerable: true },
+    altKey: { enumerable: true },
+    metaKey: { enumerable: true },
+    ctrlKey: { enumerable: true },
+    shiftKey: { enumerable: true },
+    [Symbol.toStringTag]: { value: "TouchEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = TouchEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: TouchEvent
+  });
+};
+
+const Impl = require("../events/TouchEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/TouchEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/TouchEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/TouchEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,89 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventModifierInit = require("./EventModifierInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventModifierInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "changedTouches";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (!utils.isObject(value)) {
+        throw new TypeError(context + " has member 'changedTouches' that" + " is not an iterable object.");
+      } else {
+        const V = [];
+        const tmp = value;
+        for (let nextItem of tmp) {
+          nextItem = utils.tryImplForWrapper(nextItem);
+
+          V.push(nextItem);
+        }
+        value = V;
+      }
+
+      ret[key] = value;
+    } else {
+      ret[key] = [];
+    }
+  }
+
+  {
+    const key = "targetTouches";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (!utils.isObject(value)) {
+        throw new TypeError(context + " has member 'targetTouches' that" + " is not an iterable object.");
+      } else {
+        const V = [];
+        const tmp = value;
+        for (let nextItem of tmp) {
+          nextItem = utils.tryImplForWrapper(nextItem);
+
+          V.push(nextItem);
+        }
+        value = V;
+      }
+
+      ret[key] = value;
+    } else {
+      ret[key] = [];
+    }
+  }
+
+  {
+    const key = "touches";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (!utils.isObject(value)) {
+        throw new TypeError(context + " has member 'touches' that" + " is not an iterable object.");
+      } else {
+        const V = [];
+        const tmp = value;
+        for (let nextItem of tmp) {
+          nextItem = utils.tryImplForWrapper(nextItem);
+
+          V.push(nextItem);
+        }
+        value = V;
+      }
+
+      ret[key] = value;
+    } else {
+      ret[key] = [];
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/TreeWalker.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/TreeWalker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/TreeWalker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,236 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "TreeWalker";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'TreeWalker'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["TreeWalker"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor TreeWalker is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class TreeWalker {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    parentNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'parentNode' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].parentNode());
+    }
+
+    firstChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'firstChild' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].firstChild());
+    }
+
+    lastChild() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'lastChild' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].lastChild());
+    }
+
+    previousSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'previousSibling' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].previousSibling());
+    }
+
+    nextSibling() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'nextSibling' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].nextSibling());
+    }
+
+    previousNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'previousNode' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].previousNode());
+    }
+
+    nextNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'nextNode' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol].nextNode());
+    }
+
+    get root() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get root' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.getSameObject(this, "root", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["root"]);
+      });
+    }
+
+    get whatToShow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get whatToShow' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return esValue[implSymbol]["whatToShow"];
+    }
+
+    get filter() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get filter' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["filter"]);
+    }
+
+    get currentNode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get currentNode' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["currentNode"]);
+    }
+
+    set currentNode(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set currentNode' called on an object that is not a valid instance of TreeWalker.");
+      }
+
+      V = Node.convert(V, { context: "Failed to set the 'currentNode' property on 'TreeWalker': The provided value" });
+
+      esValue[implSymbol]["currentNode"] = V;
+    }
+  }
+  Object.defineProperties(TreeWalker.prototype, {
+    parentNode: { enumerable: true },
+    firstChild: { enumerable: true },
+    lastChild: { enumerable: true },
+    previousSibling: { enumerable: true },
+    nextSibling: { enumerable: true },
+    previousNode: { enumerable: true },
+    nextNode: { enumerable: true },
+    root: { enumerable: true },
+    whatToShow: { enumerable: true },
+    filter: { enumerable: true },
+    currentNode: { enumerable: true },
+    [Symbol.toStringTag]: { value: "TreeWalker", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = TreeWalker;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: TreeWalker
+  });
+};
+
+const Impl = require("../traversal/TreeWalker-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/UIEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/UIEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/UIEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,235 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const UIEventInit = require("./UIEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Event = require("./Event.js");
+
+const interfaceName = "UIEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'UIEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["UIEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor UIEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Event._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Event === undefined) {
+    throw new Error("Internal error: attempting to evaluate UIEvent before Event");
+  }
+  class UIEvent extends globalObject.Event {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'UIEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'UIEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = UIEventInit.convert(curArg, { context: "Failed to construct 'UIEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    initUIEvent(typeArg) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'initUIEvent' called on an object that is not a valid instance of UIEvent.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'initUIEvent' on 'UIEvent': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'initUIEvent' on 'UIEvent': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initUIEvent' on 'UIEvent': parameter 2"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[2];
+        if (curArg !== undefined) {
+          curArg = conversions["boolean"](curArg, {
+            context: "Failed to execute 'initUIEvent' on 'UIEvent': parameter 3"
+          });
+        } else {
+          curArg = false;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[3];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            curArg = utils.tryImplForWrapper(curArg);
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[4];
+        if (curArg !== undefined) {
+          curArg = conversions["long"](curArg, {
+            context: "Failed to execute 'initUIEvent' on 'UIEvent': parameter 5"
+          });
+        } else {
+          curArg = 0;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].initUIEvent(...args);
+    }
+
+    get view() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get view' called on an object that is not a valid instance of UIEvent.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["view"]);
+    }
+
+    get detail() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get detail' called on an object that is not a valid instance of UIEvent.");
+      }
+
+      return esValue[implSymbol]["detail"];
+    }
+
+    get which() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get which' called on an object that is not a valid instance of UIEvent.");
+      }
+
+      return esValue[implSymbol]["which"];
+    }
+  }
+  Object.defineProperties(UIEvent.prototype, {
+    initUIEvent: { enumerable: true },
+    view: { enumerable: true },
+    detail: { enumerable: true },
+    which: { enumerable: true },
+    [Symbol.toStringTag]: { value: "UIEvent", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = UIEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: UIEvent
+  });
+};
+
+const Impl = require("../events/UIEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/UIEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/UIEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/UIEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventInit = require("./EventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  EventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "detail";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["long"](value, { context: context + " has member 'detail' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "view";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      if (value === null || value === undefined) {
+        value = null;
+      } else {
+        value = utils.tryImplForWrapper(value);
+      }
+      ret[key] = value;
+    } else {
+      ret[key] = null;
+    }
+  }
+
+  {
+    const key = "which";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'which' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/ValidityState.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/ValidityState.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/ValidityState.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,228 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "ValidityState";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'ValidityState'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["ValidityState"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor ValidityState is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class ValidityState {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get valueMissing() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get valueMissing' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["valueMissing"];
+    }
+
+    get typeMismatch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get typeMismatch' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["typeMismatch"];
+    }
+
+    get patternMismatch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get patternMismatch' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["patternMismatch"];
+    }
+
+    get tooLong() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tooLong' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["tooLong"];
+    }
+
+    get tooShort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get tooShort' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["tooShort"];
+    }
+
+    get rangeUnderflow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rangeUnderflow' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["rangeUnderflow"];
+    }
+
+    get rangeOverflow() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get rangeOverflow' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["rangeOverflow"];
+    }
+
+    get stepMismatch() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get stepMismatch' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["stepMismatch"];
+    }
+
+    get badInput() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get badInput' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["badInput"];
+    }
+
+    get customError() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get customError' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["customError"];
+    }
+
+    get valid() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get valid' called on an object that is not a valid instance of ValidityState.");
+      }
+
+      return esValue[implSymbol]["valid"];
+    }
+  }
+  Object.defineProperties(ValidityState.prototype, {
+    valueMissing: { enumerable: true },
+    typeMismatch: { enumerable: true },
+    patternMismatch: { enumerable: true },
+    tooLong: { enumerable: true },
+    tooShort: { enumerable: true },
+    rangeUnderflow: { enumerable: true },
+    rangeOverflow: { enumerable: true },
+    stepMismatch: { enumerable: true },
+    badInput: { enumerable: true },
+    customError: { enumerable: true },
+    valid: { enumerable: true },
+    [Symbol.toStringTag]: { value: "ValidityState", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = ValidityState;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: ValidityState
+  });
+};
+
+const Impl = require("../constraint-validation/ValidityState-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/VisibilityState.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/VisibilityState.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/VisibilityState.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["hidden", "visible", "prerender"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for VisibilityState`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/VoidFunction.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/VoidFunction.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/VoidFunction.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,30 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (typeof value !== "function") {
+    throw new TypeError(context + " is not a function");
+  }
+
+  function invokeTheCallbackFunction() {
+    if (new.target !== undefined) {
+      throw new Error("Internal error: invokeTheCallbackFunction is not a constructor");
+    }
+
+    const thisArg = utils.tryWrapperForImpl(this);
+    let callResult;
+
+    callResult = Reflect.apply(value, thisArg, []);
+  }
+
+  invokeTheCallbackFunction.construct = () => {
+    let callResult = Reflect.construct(value, []);
+  };
+
+  invokeTheCallbackFunction[utils.wrapperSymbol] = value;
+  invokeTheCallbackFunction.objectReference = value;
+
+  return invokeTheCallbackFunction;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/WebSocket.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/WebSocket.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/WebSocket.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,444 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Blob = require("./Blob.js");
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const BinaryType = require("./BinaryType.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const EventTarget = require("./EventTarget.js");
+
+const interfaceName = "WebSocket";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'WebSocket'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["WebSocket"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor WebSocket is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  EventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "Worker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.EventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate WebSocket before EventTarget");
+  }
+  class WebSocket extends globalObject.EventTarget {
+    constructor(url) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'WebSocket': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["USVString"](curArg, { context: "Failed to construct 'WebSocket': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          if (utils.isObject(curArg)) {
+            if (curArg[Symbol.iterator] !== undefined) {
+              if (!utils.isObject(curArg)) {
+                throw new TypeError(
+                  "Failed to construct 'WebSocket': parameter 2" + " sequence" + " is not an iterable object."
+                );
+              } else {
+                const V = [];
+                const tmp = curArg;
+                for (let nextItem of tmp) {
+                  nextItem = conversions["DOMString"](nextItem, {
+                    context: "Failed to construct 'WebSocket': parameter 2" + " sequence" + "'s element"
+                  });
+
+                  V.push(nextItem);
+                }
+                curArg = V;
+              }
+            } else {
+            }
+          } else {
+            curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'WebSocket': parameter 2" });
+          }
+        } else {
+          curArg = [];
+        }
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    close() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'close' called on an object that is not a valid instance of WebSocket.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          curArg = conversions["unsigned short"](curArg, {
+            context: "Failed to execute 'close' on 'WebSocket': parameter 1",
+            clamp: true
+          });
+        }
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        if (curArg !== undefined) {
+          curArg = conversions["USVString"](curArg, {
+            context: "Failed to execute 'close' on 'WebSocket': parameter 2"
+          });
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].close(...args);
+    }
+
+    send(data) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'send' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'send' on 'WebSocket': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (Blob.is(curArg)) {
+          {
+            let curArg = arguments[0];
+            curArg = Blob.convert(curArg, { context: "Failed to execute 'send' on 'WebSocket': parameter 1" });
+            args.push(curArg);
+          }
+        } else if (utils.isArrayBuffer(curArg)) {
+          {
+            let curArg = arguments[0];
+            curArg = conversions["ArrayBuffer"](curArg, {
+              context: "Failed to execute 'send' on 'WebSocket': parameter 1"
+            });
+            args.push(curArg);
+          }
+        } else if (ArrayBuffer.isView(curArg)) {
+          {
+            let curArg = arguments[0];
+            if (ArrayBuffer.isView(curArg)) {
+            } else {
+              throw new TypeError(
+                "Failed to execute 'send' on 'WebSocket': parameter 1" + " is not of any supported type."
+              );
+            }
+            args.push(curArg);
+          }
+        } else {
+          {
+            let curArg = arguments[0];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'send' on 'WebSocket': parameter 1"
+            });
+            args.push(curArg);
+          }
+        }
+      }
+      return esValue[implSymbol].send(...args);
+    }
+
+    get url() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get url' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return esValue[implSymbol]["url"];
+    }
+
+    get readyState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readyState' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return esValue[implSymbol]["readyState"];
+    }
+
+    get bufferedAmount() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get bufferedAmount' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return esValue[implSymbol]["bufferedAmount"];
+    }
+
+    get onopen() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onopen' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onopen"]);
+    }
+
+    set onopen(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onopen' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onopen' property on 'WebSocket': The provided value"
+        });
+      }
+      esValue[implSymbol]["onopen"] = V;
+    }
+
+    get onerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onerror' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onerror"]);
+    }
+
+    set onerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onerror' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'WebSocket': The provided value"
+        });
+      }
+      esValue[implSymbol]["onerror"] = V;
+    }
+
+    get onclose() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onclose' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onclose"]);
+    }
+
+    set onclose(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onclose' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onclose' property on 'WebSocket': The provided value"
+        });
+      }
+      esValue[implSymbol]["onclose"] = V;
+    }
+
+    get extensions() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get extensions' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return esValue[implSymbol]["extensions"];
+    }
+
+    get protocol() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get protocol' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return esValue[implSymbol]["protocol"];
+    }
+
+    get onmessage() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get onmessage' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onmessage"]);
+    }
+
+    set onmessage(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set onmessage' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onmessage' property on 'WebSocket': The provided value"
+        });
+      }
+      esValue[implSymbol]["onmessage"] = V;
+    }
+
+    get binaryType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get binaryType' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["binaryType"]);
+    }
+
+    set binaryType(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set binaryType' called on an object that is not a valid instance of WebSocket.");
+      }
+
+      V = `${V}`;
+      if (!BinaryType.enumerationValues.has(V)) {
+        return;
+      }
+
+      esValue[implSymbol]["binaryType"] = V;
+    }
+  }
+  Object.defineProperties(WebSocket.prototype, {
+    close: { enumerable: true },
+    send: { enumerable: true },
+    url: { enumerable: true },
+    readyState: { enumerable: true },
+    bufferedAmount: { enumerable: true },
+    onopen: { enumerable: true },
+    onerror: { enumerable: true },
+    onclose: { enumerable: true },
+    extensions: { enumerable: true },
+    protocol: { enumerable: true },
+    onmessage: { enumerable: true },
+    binaryType: { enumerable: true },
+    [Symbol.toStringTag]: { value: "WebSocket", configurable: true },
+    CONNECTING: { value: 0, enumerable: true },
+    OPEN: { value: 1, enumerable: true },
+    CLOSING: { value: 2, enumerable: true },
+    CLOSED: { value: 3, enumerable: true }
+  });
+  Object.defineProperties(WebSocket, {
+    CONNECTING: { value: 0, enumerable: true },
+    OPEN: { value: 1, enumerable: true },
+    CLOSING: { value: 2, enumerable: true },
+    CLOSED: { value: 3, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = WebSocket;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: WebSocket
+  });
+};
+
+const Impl = require("../websockets/WebSocket-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/WheelEvent.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/WheelEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/WheelEvent.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,183 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const WheelEventInit = require("./WheelEventInit.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const MouseEvent = require("./MouseEvent.js");
+
+const interfaceName = "WheelEvent";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'WheelEvent'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["WheelEvent"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor WheelEvent is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  MouseEvent._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.MouseEvent === undefined) {
+    throw new Error("Internal error: attempting to evaluate WheelEvent before MouseEvent");
+  }
+  class WheelEvent extends globalObject.MouseEvent {
+    constructor(type) {
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to construct 'WheelEvent': 1 argument required, but only " + arguments.length + " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, { context: "Failed to construct 'WheelEvent': parameter 1" });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = WheelEventInit.convert(curArg, { context: "Failed to construct 'WheelEvent': parameter 2" });
+        args.push(curArg);
+      }
+      return exports.setup(Object.create(new.target.prototype), globalObject, args);
+    }
+
+    get deltaX() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get deltaX' called on an object that is not a valid instance of WheelEvent.");
+      }
+
+      return esValue[implSymbol]["deltaX"];
+    }
+
+    get deltaY() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get deltaY' called on an object that is not a valid instance of WheelEvent.");
+      }
+
+      return esValue[implSymbol]["deltaY"];
+    }
+
+    get deltaZ() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get deltaZ' called on an object that is not a valid instance of WheelEvent.");
+      }
+
+      return esValue[implSymbol]["deltaZ"];
+    }
+
+    get deltaMode() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get deltaMode' called on an object that is not a valid instance of WheelEvent.");
+      }
+
+      return esValue[implSymbol]["deltaMode"];
+    }
+  }
+  Object.defineProperties(WheelEvent.prototype, {
+    deltaX: { enumerable: true },
+    deltaY: { enumerable: true },
+    deltaZ: { enumerable: true },
+    deltaMode: { enumerable: true },
+    [Symbol.toStringTag]: { value: "WheelEvent", configurable: true },
+    DOM_DELTA_PIXEL: { value: 0x00, enumerable: true },
+    DOM_DELTA_LINE: { value: 0x01, enumerable: true },
+    DOM_DELTA_PAGE: { value: 0x02, enumerable: true }
+  });
+  Object.defineProperties(WheelEvent, {
+    DOM_DELTA_PIXEL: { value: 0x00, enumerable: true },
+    DOM_DELTA_LINE: { value: 0x01, enumerable: true },
+    DOM_DELTA_PAGE: { value: 0x02, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = WheelEvent;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: WheelEvent
+  });
+};
+
+const Impl = require("../events/WheelEvent-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/WheelEventInit.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/WheelEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/WheelEventInit.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,68 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const MouseEventInit = require("./MouseEventInit.js");
+
+exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
+  MouseEventInit._convertInherit(obj, ret, { context });
+
+  {
+    const key = "deltaMode";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["unsigned long"](value, { context: context + " has member 'deltaMode' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0;
+    }
+  }
+
+  {
+    const key = "deltaX";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["double"](value, { context: context + " has member 'deltaX' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0.0;
+    }
+  }
+
+  {
+    const key = "deltaY";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["double"](value, { context: context + " has member 'deltaY' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0.0;
+    }
+  }
+
+  {
+    const key = "deltaZ";
+    let value = obj === undefined || obj === null ? undefined : obj[key];
+    if (value !== undefined) {
+      value = conversions["double"](value, { context: context + " has member 'deltaZ' that" });
+
+      ret[key] = value;
+    } else {
+      ret[key] = 0.0;
+    }
+  }
+};
+
+exports.convert = function convert(obj, { context = "The provided value" } = {}) {
+  if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
+    throw new TypeError(`${context} is not an object.`);
+  }
+
+  const ret = Object.create(null);
+  exports._convertInherit(obj, ret, { context });
+  return ret;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLDocument.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLDocument.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLDocument.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const Document = require("./Document.js");
+
+const interfaceName = "XMLDocument";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'XMLDocument'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["XMLDocument"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor XMLDocument is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  Document._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.Document === undefined) {
+    throw new Error("Internal error: attempting to evaluate XMLDocument before Document");
+  }
+  class XMLDocument extends globalObject.Document {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(XMLDocument.prototype, {
+    [Symbol.toStringTag]: { value: "XMLDocument", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = XMLDocument;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: XMLDocument
+  });
+};
+
+const Impl = require("../nodes/XMLDocument-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequest.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequest.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,617 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Document = require("./Document.js");
+const Blob = require("./Blob.js");
+const FormData = require("./FormData.js");
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const XMLHttpRequestResponseType = require("./XMLHttpRequestResponseType.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const XMLHttpRequestEventTarget = require("./XMLHttpRequestEventTarget.js");
+
+const interfaceName = "XMLHttpRequest";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'XMLHttpRequest'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["XMLHttpRequest"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor XMLHttpRequest is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  XMLHttpRequestEventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "DedicatedWorker", "SharedWorker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.XMLHttpRequestEventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate XMLHttpRequest before XMLHttpRequestEventTarget");
+  }
+  class XMLHttpRequest extends globalObject.XMLHttpRequestEventTarget {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    open(method, url) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'open' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'open' on 'XMLHttpRequest': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      switch (arguments.length) {
+        case 2:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["ByteString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2"
+            });
+            args.push(curArg);
+          }
+          break;
+        case 3:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["ByteString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 3"
+            });
+            args.push(curArg);
+          }
+          break;
+        case 4:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["ByteString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 3"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[3];
+            if (curArg !== undefined) {
+              if (curArg === null || curArg === undefined) {
+                curArg = null;
+              } else {
+                curArg = conversions["USVString"](curArg, {
+                  context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 4"
+                });
+              }
+            } else {
+              curArg = null;
+            }
+            args.push(curArg);
+          }
+          break;
+        default:
+          {
+            let curArg = arguments[0];
+            curArg = conversions["ByteString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 1"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[1];
+            curArg = conversions["USVString"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 2"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[2];
+            curArg = conversions["boolean"](curArg, {
+              context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 3"
+            });
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[3];
+            if (curArg !== undefined) {
+              if (curArg === null || curArg === undefined) {
+                curArg = null;
+              } else {
+                curArg = conversions["USVString"](curArg, {
+                  context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 4"
+                });
+              }
+            } else {
+              curArg = null;
+            }
+            args.push(curArg);
+          }
+          {
+            let curArg = arguments[4];
+            if (curArg !== undefined) {
+              if (curArg === null || curArg === undefined) {
+                curArg = null;
+              } else {
+                curArg = conversions["USVString"](curArg, {
+                  context: "Failed to execute 'open' on 'XMLHttpRequest': parameter 5"
+                });
+              }
+            } else {
+              curArg = null;
+            }
+            args.push(curArg);
+          }
+      }
+      return esValue[implSymbol].open(...args);
+    }
+
+    setRequestHeader(name, value) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'setRequestHeader' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      if (arguments.length < 2) {
+        throw new TypeError(
+          "Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 2 arguments required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, {
+          context: "Failed to execute 'setRequestHeader' on 'XMLHttpRequest': parameter 1"
+        });
+        args.push(curArg);
+      }
+      {
+        let curArg = arguments[1];
+        curArg = conversions["ByteString"](curArg, {
+          context: "Failed to execute 'setRequestHeader' on 'XMLHttpRequest': parameter 2"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].setRequestHeader(...args);
+    }
+
+    send() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'send' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        if (curArg !== undefined) {
+          if (curArg === null || curArg === undefined) {
+            curArg = null;
+          } else {
+            if (Document.is(curArg) || Blob.is(curArg) || FormData.is(curArg)) {
+              curArg = utils.implForWrapper(curArg);
+            } else if (utils.isArrayBuffer(curArg)) {
+            } else if (ArrayBuffer.isView(curArg)) {
+            } else {
+              curArg = conversions["USVString"](curArg, {
+                context: "Failed to execute 'send' on 'XMLHttpRequest': parameter 1"
+              });
+            }
+          }
+        } else {
+          curArg = null;
+        }
+        args.push(curArg);
+      }
+      return esValue[implSymbol].send(...args);
+    }
+
+    abort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'abort' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol].abort();
+    }
+
+    getResponseHeader(name) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'getResponseHeader' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'getResponseHeader' on 'XMLHttpRequest': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["ByteString"](curArg, {
+          context: "Failed to execute 'getResponseHeader' on 'XMLHttpRequest': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].getResponseHeader(...args);
+    }
+
+    getAllResponseHeaders() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'getAllResponseHeaders' called on an object that is not a valid instance of XMLHttpRequest."
+        );
+      }
+
+      return esValue[implSymbol].getAllResponseHeaders();
+    }
+
+    overrideMimeType(mime) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'overrideMimeType' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'overrideMimeType' on 'XMLHttpRequest': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = conversions["DOMString"](curArg, {
+          context: "Failed to execute 'overrideMimeType' on 'XMLHttpRequest': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].overrideMimeType(...args);
+    }
+
+    get onreadystatechange() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onreadystatechange' called on an object that is not a valid instance of XMLHttpRequest."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onreadystatechange"]);
+    }
+
+    set onreadystatechange(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onreadystatechange' called on an object that is not a valid instance of XMLHttpRequest."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onreadystatechange' property on 'XMLHttpRequest': The provided value"
+        });
+      }
+      esValue[implSymbol]["onreadystatechange"] = V;
+    }
+
+    get readyState() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get readyState' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["readyState"];
+    }
+
+    get timeout() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get timeout' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["timeout"];
+    }
+
+    set timeout(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set timeout' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      V = conversions["unsigned long"](V, {
+        context: "Failed to set the 'timeout' property on 'XMLHttpRequest': The provided value"
+      });
+
+      esValue[implSymbol]["timeout"] = V;
+    }
+
+    get withCredentials() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get withCredentials' called on an object that is not a valid instance of XMLHttpRequest."
+        );
+      }
+
+      return esValue[implSymbol]["withCredentials"];
+    }
+
+    set withCredentials(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set withCredentials' called on an object that is not a valid instance of XMLHttpRequest."
+        );
+      }
+
+      V = conversions["boolean"](V, {
+        context: "Failed to set the 'withCredentials' property on 'XMLHttpRequest': The provided value"
+      });
+
+      esValue[implSymbol]["withCredentials"] = V;
+    }
+
+    get upload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get upload' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return utils.getSameObject(this, "upload", () => {
+        return utils.tryWrapperForImpl(esValue[implSymbol]["upload"]);
+      });
+    }
+
+    get responseURL() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get responseURL' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["responseURL"];
+    }
+
+    get status() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get status' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["status"];
+    }
+
+    get statusText() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get statusText' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["statusText"];
+    }
+
+    get responseType() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get responseType' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["responseType"]);
+    }
+
+    set responseType(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'set responseType' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      V = `${V}`;
+      if (!XMLHttpRequestResponseType.enumerationValues.has(V)) {
+        return;
+      }
+
+      esValue[implSymbol]["responseType"] = V;
+    }
+
+    get response() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get response' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["response"];
+    }
+
+    get responseText() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get responseText' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return esValue[implSymbol]["responseText"];
+    }
+
+    get responseXML() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError("'get responseXML' called on an object that is not a valid instance of XMLHttpRequest.");
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["responseXML"]);
+    }
+  }
+  Object.defineProperties(XMLHttpRequest.prototype, {
+    open: { enumerable: true },
+    setRequestHeader: { enumerable: true },
+    send: { enumerable: true },
+    abort: { enumerable: true },
+    getResponseHeader: { enumerable: true },
+    getAllResponseHeaders: { enumerable: true },
+    overrideMimeType: { enumerable: true },
+    onreadystatechange: { enumerable: true },
+    readyState: { enumerable: true },
+    timeout: { enumerable: true },
+    withCredentials: { enumerable: true },
+    upload: { enumerable: true },
+    responseURL: { enumerable: true },
+    status: { enumerable: true },
+    statusText: { enumerable: true },
+    responseType: { enumerable: true },
+    response: { enumerable: true },
+    responseText: { enumerable: true },
+    responseXML: { enumerable: true },
+    [Symbol.toStringTag]: { value: "XMLHttpRequest", configurable: true },
+    UNSENT: { value: 0, enumerable: true },
+    OPENED: { value: 1, enumerable: true },
+    HEADERS_RECEIVED: { value: 2, enumerable: true },
+    LOADING: { value: 3, enumerable: true },
+    DONE: { value: 4, enumerable: true }
+  });
+  Object.defineProperties(XMLHttpRequest, {
+    UNSENT: { value: 0, enumerable: true },
+    OPENED: { value: 1, enumerable: true },
+    HEADERS_RECEIVED: { value: 2, enumerable: true },
+    LOADING: { value: 3, enumerable: true },
+    DONE: { value: 4, enumerable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = XMLHttpRequest;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: XMLHttpRequest
+  });
+};
+
+const Impl = require("../xhr/XMLHttpRequest-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestEventTarget.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestEventTarget.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestEventTarget.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,341 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const EventHandlerNonNull = require("./EventHandlerNonNull.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const EventTarget = require("./EventTarget.js");
+
+const interfaceName = "XMLHttpRequestEventTarget";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'XMLHttpRequestEventTarget'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["XMLHttpRequestEventTarget"];
+  if (ctor === undefined) {
+    throw new Error(
+      "Internal error: constructor XMLHttpRequestEventTarget is not installed on the passed global object"
+    );
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  EventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "DedicatedWorker", "SharedWorker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.EventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate XMLHttpRequestEventTarget before EventTarget");
+  }
+  class XMLHttpRequestEventTarget extends globalObject.EventTarget {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+
+    get onloadstart() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onloadstart' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadstart"]);
+    }
+
+    set onloadstart(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onloadstart' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadstart' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadstart"] = V;
+    }
+
+    get onprogress() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onprogress' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onprogress"]);
+    }
+
+    set onprogress(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onprogress' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onprogress' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["onprogress"] = V;
+    }
+
+    get onabort() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onabort' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onabort"]);
+    }
+
+    set onabort(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onabort' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onabort' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["onabort"] = V;
+    }
+
+    get onerror() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onerror' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onerror"]);
+    }
+
+    set onerror(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onerror' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onerror' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["onerror"] = V;
+    }
+
+    get onload() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onload' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onload"]);
+    }
+
+    set onload(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onload' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onload' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["onload"] = V;
+    }
+
+    get ontimeout() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get ontimeout' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["ontimeout"]);
+    }
+
+    set ontimeout(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set ontimeout' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'ontimeout' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["ontimeout"] = V;
+    }
+
+    get onloadend() {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'get onloadend' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      return utils.tryWrapperForImpl(esValue[implSymbol]["onloadend"]);
+    }
+
+    set onloadend(V) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+
+      if (!exports.is(esValue)) {
+        throw new TypeError(
+          "'set onloadend' called on an object that is not a valid instance of XMLHttpRequestEventTarget."
+        );
+      }
+
+      if (!utils.isObject(V)) {
+        V = null;
+      } else {
+        V = EventHandlerNonNull.convert(V, {
+          context: "Failed to set the 'onloadend' property on 'XMLHttpRequestEventTarget': The provided value"
+        });
+      }
+      esValue[implSymbol]["onloadend"] = V;
+    }
+  }
+  Object.defineProperties(XMLHttpRequestEventTarget.prototype, {
+    onloadstart: { enumerable: true },
+    onprogress: { enumerable: true },
+    onabort: { enumerable: true },
+    onerror: { enumerable: true },
+    onload: { enumerable: true },
+    ontimeout: { enumerable: true },
+    onloadend: { enumerable: true },
+    [Symbol.toStringTag]: { value: "XMLHttpRequestEventTarget", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = XMLHttpRequestEventTarget;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: XMLHttpRequestEventTarget
+  });
+};
+
+const Impl = require("../xhr/XMLHttpRequestEventTarget-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestResponseType.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestResponseType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestResponseType.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+const enumerationValues = new Set(["", "arraybuffer", "blob", "document", "json", "text"]);
+exports.enumerationValues = enumerationValues;
+
+exports.convert = function convert(value, { context = "The provided value" } = {}) {
+  const string = `${value}`;
+  if (!enumerationValues.has(string)) {
+    throw new TypeError(`${context} '${string}' is not a valid enumeration value for XMLHttpRequestResponseType`);
+  }
+  return string;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestUpload.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestUpload.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLHttpRequestUpload.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+const XMLHttpRequestEventTarget = require("./XMLHttpRequestEventTarget.js");
+
+const interfaceName = "XMLHttpRequestUpload";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'XMLHttpRequestUpload'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["XMLHttpRequestUpload"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor XMLHttpRequestUpload is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {
+  XMLHttpRequestEventTarget._internalSetup(wrapper, globalObject);
+};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window", "DedicatedWorker", "SharedWorker"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+
+  if (globalObject.XMLHttpRequestEventTarget === undefined) {
+    throw new Error("Internal error: attempting to evaluate XMLHttpRequestUpload before XMLHttpRequestEventTarget");
+  }
+  class XMLHttpRequestUpload extends globalObject.XMLHttpRequestEventTarget {
+    constructor() {
+      throw new TypeError("Illegal constructor");
+    }
+  }
+  Object.defineProperties(XMLHttpRequestUpload.prototype, {
+    [Symbol.toStringTag]: { value: "XMLHttpRequestUpload", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = XMLHttpRequestUpload;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: XMLHttpRequestUpload
+  });
+};
+
+const Impl = require("../xhr/XMLHttpRequestUpload-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLSerializer.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLSerializer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/XMLSerializer.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,133 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const utils = require("./utils.js");
+
+const Node = require("./Node.js");
+const implSymbol = utils.implSymbol;
+const ctorRegistrySymbol = utils.ctorRegistrySymbol;
+
+const interfaceName = "XMLSerializer";
+
+exports.is = value => {
+  return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
+};
+exports.isImpl = value => {
+  return utils.isObject(value) && value instanceof Impl.implementation;
+};
+exports.convert = (value, { context = "The provided value" } = {}) => {
+  if (exports.is(value)) {
+    return utils.implForWrapper(value);
+  }
+  throw new TypeError(`${context} is not of type 'XMLSerializer'.`);
+};
+
+function makeWrapper(globalObject) {
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    throw new Error("Internal error: invalid global object");
+  }
+
+  const ctor = globalObject[ctorRegistrySymbol]["XMLSerializer"];
+  if (ctor === undefined) {
+    throw new Error("Internal error: constructor XMLSerializer is not installed on the passed global object");
+  }
+
+  return Object.create(ctor.prototype);
+}
+
+exports.create = (globalObject, constructorArgs, privateData) => {
+  const wrapper = makeWrapper(globalObject);
+  return exports.setup(wrapper, globalObject, constructorArgs, privateData);
+};
+
+exports.createImpl = (globalObject, constructorArgs, privateData) => {
+  const wrapper = exports.create(globalObject, constructorArgs, privateData);
+  return utils.implForWrapper(wrapper);
+};
+
+exports._internalSetup = (wrapper, globalObject) => {};
+
+exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
+  privateData.wrapper = wrapper;
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: new Impl.implementation(globalObject, constructorArgs, privateData),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper;
+};
+
+exports.new = globalObject => {
+  const wrapper = makeWrapper(globalObject);
+
+  exports._internalSetup(wrapper, globalObject);
+  Object.defineProperty(wrapper, implSymbol, {
+    value: Object.create(Impl.implementation.prototype),
+    configurable: true
+  });
+
+  wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
+  if (Impl.init) {
+    Impl.init(wrapper[implSymbol]);
+  }
+  return wrapper[implSymbol];
+};
+
+const exposed = new Set(["Window"]);
+
+exports.install = (globalObject, globalNames) => {
+  if (!globalNames.some(globalName => exposed.has(globalName))) {
+    return;
+  }
+  class XMLSerializer {
+    constructor() {
+      return exports.setup(Object.create(new.target.prototype), globalObject, undefined);
+    }
+
+    serializeToString(root) {
+      const esValue = this !== null && this !== undefined ? this : globalObject;
+      if (!exports.is(esValue)) {
+        throw new TypeError("'serializeToString' called on an object that is not a valid instance of XMLSerializer.");
+      }
+
+      if (arguments.length < 1) {
+        throw new TypeError(
+          "Failed to execute 'serializeToString' on 'XMLSerializer': 1 argument required, but only " +
+            arguments.length +
+            " present."
+        );
+      }
+      const args = [];
+      {
+        let curArg = arguments[0];
+        curArg = Node.convert(curArg, {
+          context: "Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1"
+        });
+        args.push(curArg);
+      }
+      return esValue[implSymbol].serializeToString(...args);
+    }
+  }
+  Object.defineProperties(XMLSerializer.prototype, {
+    serializeToString: { enumerable: true },
+    [Symbol.toStringTag]: { value: "XMLSerializer", configurable: true }
+  });
+  if (globalObject[ctorRegistrySymbol] === undefined) {
+    globalObject[ctorRegistrySymbol] = Object.create(null);
+  }
+  globalObject[ctorRegistrySymbol][interfaceName] = XMLSerializer;
+
+  Object.defineProperty(globalObject, interfaceName, {
+    configurable: true,
+    writable: true,
+    value: XMLSerializer
+  });
+};
+
+const Impl = require("../domparsing/XMLSerializer-impl.js");
Index: frontend/node_modules/jsdom/lib/jsdom/living/generated/utils.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/generated/utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/generated/utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,141 @@
+"use strict";
+
+// Returns "Type(value) is Object" in ES terminology.
+function isObject(value) {
+  return typeof value === "object" && value !== null || typeof value === "function";
+}
+
+const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty);
+
+const wrapperSymbol = Symbol("wrapper");
+const implSymbol = Symbol("impl");
+const sameObjectCaches = Symbol("SameObject caches");
+const ctorRegistrySymbol = Symbol.for("[webidl2js]  constructor registry");
+
+function getSameObject(wrapper, prop, creator) {
+  if (!wrapper[sameObjectCaches]) {
+    wrapper[sameObjectCaches] = Object.create(null);
+  }
+
+  if (prop in wrapper[sameObjectCaches]) {
+    return wrapper[sameObjectCaches][prop];
+  }
+
+  wrapper[sameObjectCaches][prop] = creator();
+  return wrapper[sameObjectCaches][prop];
+}
+
+function wrapperForImpl(impl) {
+  return impl ? impl[wrapperSymbol] : null;
+}
+
+function implForWrapper(wrapper) {
+  return wrapper ? wrapper[implSymbol] : null;
+}
+
+function tryWrapperForImpl(impl) {
+  const wrapper = wrapperForImpl(impl);
+  return wrapper ? wrapper : impl;
+}
+
+function tryImplForWrapper(wrapper) {
+  const impl = implForWrapper(wrapper);
+  return impl ? impl : wrapper;
+}
+
+const iterInternalSymbol = Symbol("internal");
+const IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
+const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype);
+
+function isArrayIndexPropName(P) {
+  if (typeof P !== "string") {
+    return false;
+  }
+  const i = P >>> 0;
+  if (i === Math.pow(2, 32) - 1) {
+    return false;
+  }
+  const s = `${i}`;
+  if (P !== s) {
+    return false;
+  }
+  return true;
+}
+
+const byteLengthGetter =
+    Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get;
+function isArrayBuffer(value) {
+  try {
+    byteLengthGetter.call(value);
+    return true;
+  } catch (e) {
+    return false;
+  }
+}
+
+function iteratorResult([key, value], kind) {
+  let result;
+  switch (kind) {
+    case "key":
+      result = key;
+      break;
+    case "value":
+      result = value;
+      break;
+    case "key+value":
+      result = [key, value];
+      break;
+  }
+  return { value: result, done: false };
+}
+
+const supportsPropertyIndex = Symbol("supports property index");
+const supportedPropertyIndices = Symbol("supported property indices");
+const supportsPropertyName = Symbol("supports property name");
+const supportedPropertyNames = Symbol("supported property names");
+const indexedGet = Symbol("indexed property get");
+const indexedSetNew = Symbol("indexed property set new");
+const indexedSetExisting = Symbol("indexed property set existing");
+const namedGet = Symbol("named property get");
+const namedSetNew = Symbol("named property set new");
+const namedSetExisting = Symbol("named property set existing");
+const namedDelete = Symbol("named property delete");
+
+const asyncIteratorNext = Symbol("async iterator get the next iteration result");
+const asyncIteratorReturn = Symbol("async iterator return steps");
+const asyncIteratorInit = Symbol("async iterator initialization steps");
+const asyncIteratorEOI = Symbol("async iterator end of iteration");
+
+module.exports = exports = {
+  isObject,
+  hasOwn,
+  wrapperSymbol,
+  implSymbol,
+  getSameObject,
+  ctorRegistrySymbol,
+  wrapperForImpl,
+  implForWrapper,
+  tryWrapperForImpl,
+  tryImplForWrapper,
+  iterInternalSymbol,
+  IteratorPrototype,
+  AsyncIteratorPrototype,
+  isArrayBuffer,
+  isArrayIndexPropName,
+  supportsPropertyIndex,
+  supportedPropertyIndices,
+  supportsPropertyName,
+  supportedPropertyNames,
+  indexedGet,
+  indexedSetNew,
+  indexedSetExisting,
+  namedGet,
+  namedSetNew,
+  namedSetExisting,
+  namedDelete,
+  asyncIteratorNext,
+  asyncIteratorReturn,
+  asyncIteratorInit,
+  asyncIteratorEOI,
+  iteratorResult
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/agent-factory.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/agent-factory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/agent-factory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+const http = require("http");
+const https = require("https");
+const { parse: parseURLToNodeOptions } = require("url");
+const HttpProxyAgent = require("http-proxy-agent");
+const HttpsProxyAgent = require("https-proxy-agent");
+
+module.exports = function agentFactory(proxy, rejectUnauthorized) {
+  const agentOpts = { keepAlive: true, rejectUnauthorized };
+  if (proxy) {
+    const proxyOpts = { ...parseURLToNodeOptions(proxy), ...agentOpts };
+    return { https: new HttpsProxyAgent(proxyOpts), http: new HttpProxyAgent(proxyOpts) };
+  }
+  return { http: new http.Agent(agentOpts), https: new https.Agent(agentOpts) };
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/binary-data.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/binary-data.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/binary-data.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+// See https://github.com/jsdom/jsdom/pull/2743#issuecomment-562991955 for background.
+exports.copyToArrayBufferInNewRealm = (nodejsBuffer, newRealm) => {
+  const newAB = new newRealm.ArrayBuffer(nodejsBuffer.byteLength);
+  const view = new Uint8Array(newAB);
+  view.set(nodejsBuffer);
+  return newAB;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/create-element.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/create-element.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/create-element.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,320 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const interfaces = require("../interfaces");
+
+const { implForWrapper } = require("../generated/utils");
+
+const { HTML_NS, SVG_NS } = require("./namespaces");
+const { domSymbolTree } = require("./internal-constants");
+const { validateAndExtract } = require("./validate-names");
+const reportException = require("./runtime-script-errors");
+const {
+  isValidCustomElementName, upgradeElement, lookupCEDefinition, enqueueCEUpgradeReaction
+} = require("./custom-elements");
+
+const INTERFACE_TAG_MAPPING = {
+  // https://html.spec.whatwg.org/multipage/dom.html#elements-in-the-dom%3Aelement-interface
+  // https://html.spec.whatwg.org/multipage/indices.html#elements-3
+  [HTML_NS]: {
+    HTMLElement: [
+      "abbr", "address", "article", "aside", "b", "bdi", "bdo", "cite", "code", "dd", "dfn", "dt", "em", "figcaption",
+      "figure", "footer", "header", "hgroup", "i", "kbd", "main", "mark", "nav", "noscript", "rp", "rt", "ruby", "s",
+      "samp", "section", "small", "strong", "sub", "summary", "sup", "u", "var", "wbr"
+    ],
+    HTMLAnchorElement: ["a"],
+    HTMLAreaElement: ["area"],
+    HTMLAudioElement: ["audio"],
+    HTMLBaseElement: ["base"],
+    HTMLBodyElement: ["body"],
+    HTMLBRElement: ["br"],
+    HTMLButtonElement: ["button"],
+    HTMLCanvasElement: ["canvas"],
+    HTMLDataElement: ["data"],
+    HTMLDataListElement: ["datalist"],
+    HTMLDetailsElement: ["details"],
+    HTMLDialogElement: ["dialog"],
+    HTMLDirectoryElement: ["dir"],
+    HTMLDivElement: ["div"],
+    HTMLDListElement: ["dl"],
+    HTMLEmbedElement: ["embed"],
+    HTMLFieldSetElement: ["fieldset"],
+    HTMLFontElement: ["font"],
+    HTMLFormElement: ["form"],
+    HTMLFrameElement: ["frame"],
+    HTMLFrameSetElement: ["frameset"],
+    HTMLHeadingElement: ["h1", "h2", "h3", "h4", "h5", "h6"],
+    HTMLHeadElement: ["head"],
+    HTMLHRElement: ["hr"],
+    HTMLHtmlElement: ["html"],
+    HTMLIFrameElement: ["iframe"],
+    HTMLImageElement: ["img"],
+    HTMLInputElement: ["input"],
+    HTMLLabelElement: ["label"],
+    HTMLLegendElement: ["legend"],
+    HTMLLIElement: ["li"],
+    HTMLLinkElement: ["link"],
+    HTMLMapElement: ["map"],
+    HTMLMarqueeElement: ["marquee"],
+    HTMLMediaElement: [],
+    HTMLMenuElement: ["menu"],
+    HTMLMetaElement: ["meta"],
+    HTMLMeterElement: ["meter"],
+    HTMLModElement: ["del", "ins"],
+    HTMLObjectElement: ["object"],
+    HTMLOListElement: ["ol"],
+    HTMLOptGroupElement: ["optgroup"],
+    HTMLOptionElement: ["option"],
+    HTMLOutputElement: ["output"],
+    HTMLParagraphElement: ["p"],
+    HTMLParamElement: ["param"],
+    HTMLPictureElement: ["picture"],
+    HTMLPreElement: ["listing", "pre", "xmp"],
+    HTMLProgressElement: ["progress"],
+    HTMLQuoteElement: ["blockquote", "q"],
+    HTMLScriptElement: ["script"],
+    HTMLSelectElement: ["select"],
+    HTMLSlotElement: ["slot"],
+    HTMLSourceElement: ["source"],
+    HTMLSpanElement: ["span"],
+    HTMLStyleElement: ["style"],
+    HTMLTableCaptionElement: ["caption"],
+    HTMLTableCellElement: ["th", "td"],
+    HTMLTableColElement: ["col", "colgroup"],
+    HTMLTableElement: ["table"],
+    HTMLTimeElement: ["time"],
+    HTMLTitleElement: ["title"],
+    HTMLTableRowElement: ["tr"],
+    HTMLTableSectionElement: ["thead", "tbody", "tfoot"],
+    HTMLTemplateElement: ["template"],
+    HTMLTextAreaElement: ["textarea"],
+    HTMLTrackElement: ["track"],
+    HTMLUListElement: ["ul"],
+    HTMLUnknownElement: [],
+    HTMLVideoElement: ["video"]
+  },
+  [SVG_NS]: {
+    SVGElement: [],
+    SVGGraphicsElement: [],
+    SVGSVGElement: ["svg"],
+    SVGTitleElement: ["title"]
+  }
+};
+
+const TAG_INTERFACE_LOOKUP = {};
+
+for (const namespace of [HTML_NS, SVG_NS]) {
+  TAG_INTERFACE_LOOKUP[namespace] = {};
+
+  const interfaceNames = Object.keys(INTERFACE_TAG_MAPPING[namespace]);
+  for (const interfaceName of interfaceNames) {
+    const tagNames = INTERFACE_TAG_MAPPING[namespace][interfaceName];
+
+    for (const tagName of tagNames) {
+      TAG_INTERFACE_LOOKUP[namespace][tagName] = interfaceName;
+    }
+  }
+}
+
+const UNKNOWN_HTML_ELEMENTS_NAMES = ["applet", "bgsound", "blink", "isindex", "keygen", "multicol", "nextid", "spacer"];
+const HTML_ELEMENTS_NAMES = [
+  "acronym", "basefont", "big", "center", "nobr", "noembed", "noframes", "plaintext", "rb", "rtc",
+  "strike", "tt"
+];
+
+// https://html.spec.whatwg.org/multipage/dom.html#elements-in-the-dom:element-interface
+function getHTMLElementInterface(name) {
+  if (UNKNOWN_HTML_ELEMENTS_NAMES.includes(name)) {
+    return interfaces.getInterfaceWrapper("HTMLUnknownElement");
+  }
+
+  if (HTML_ELEMENTS_NAMES.includes(name)) {
+    return interfaces.getInterfaceWrapper("HTMLElement");
+  }
+
+  const specDefinedInterface = TAG_INTERFACE_LOOKUP[HTML_NS][name];
+  if (specDefinedInterface !== undefined) {
+    return interfaces.getInterfaceWrapper(specDefinedInterface);
+  }
+
+  if (isValidCustomElementName(name)) {
+    return interfaces.getInterfaceWrapper("HTMLElement");
+  }
+
+  return interfaces.getInterfaceWrapper("HTMLUnknownElement");
+}
+
+// https://svgwg.org/svg2-draft/types.html#ElementsInTheSVGDOM
+function getSVGInterface(name) {
+  const specDefinedInterface = TAG_INTERFACE_LOOKUP[SVG_NS][name];
+  if (specDefinedInterface !== undefined) {
+    return interfaces.getInterfaceWrapper(specDefinedInterface);
+  }
+
+  return interfaces.getInterfaceWrapper("SVGElement");
+}
+
+// Returns the list of valid tag names that can bo associated with a element given its namespace and name.
+function getValidTagNames(namespace, name) {
+  if (INTERFACE_TAG_MAPPING[namespace] && INTERFACE_TAG_MAPPING[namespace][name]) {
+    return INTERFACE_TAG_MAPPING[namespace][name];
+  }
+
+  return [];
+}
+
+// https://dom.spec.whatwg.org/#concept-create-element
+function createElement(
+  document,
+  localName,
+  namespace,
+  prefix = null,
+  isValue = null,
+  synchronousCE = false
+) {
+  let result = null;
+
+  const { _globalObject } = document;
+  const definition = lookupCEDefinition(document, namespace, localName, isValue);
+
+  if (definition !== null && definition.name !== localName) {
+    const elementInterface = getHTMLElementInterface(localName);
+
+    result = elementInterface.createImpl(_globalObject, [], {
+      ownerDocument: document,
+      localName,
+      namespace: HTML_NS,
+      prefix,
+      ceState: "undefined",
+      ceDefinition: null,
+      isValue
+    });
+
+    if (synchronousCE) {
+      upgradeElement(definition, result);
+    } else {
+      enqueueCEUpgradeReaction(result, definition);
+    }
+  } else if (definition !== null) {
+    if (synchronousCE) {
+      try {
+        const C = definition.constructor;
+
+        const resultWrapper = C.construct();
+        result = implForWrapper(resultWrapper);
+
+        if (!result._ceState || !result._ceDefinition || result._namespaceURI !== HTML_NS) {
+          throw new TypeError("Internal error: Invalid custom element.");
+        }
+
+        if (result._attributeList.length !== 0) {
+          throw DOMException.create(_globalObject, ["Unexpected attributes.", "NotSupportedError"]);
+        }
+        if (domSymbolTree.hasChildren(result)) {
+          throw DOMException.create(_globalObject, ["Unexpected child nodes.", "NotSupportedError"]);
+        }
+        if (domSymbolTree.parent(result)) {
+          throw DOMException.create(_globalObject, ["Unexpected element parent.", "NotSupportedError"]);
+        }
+        if (result._ownerDocument !== document) {
+          throw DOMException.create(_globalObject, ["Unexpected element owner document.", "NotSupportedError"]);
+        }
+        if (result._namespaceURI !== namespace) {
+          throw DOMException.create(_globalObject, ["Unexpected element namespace URI.", "NotSupportedError"]);
+        }
+        if (result._localName !== localName) {
+          throw DOMException.create(_globalObject, ["Unexpected element local name.", "NotSupportedError"]);
+        }
+
+        result._prefix = prefix;
+        result._isValue = isValue;
+      } catch (error) {
+        reportException(document._defaultView, error);
+
+        const interfaceWrapper = interfaces.getInterfaceWrapper("HTMLUnknownElement");
+        result = interfaceWrapper.createImpl(_globalObject, [], {
+          ownerDocument: document,
+          localName,
+          namespace: HTML_NS,
+          prefix,
+          ceState: "failed",
+          ceDefinition: null,
+          isValue: null
+        });
+      }
+    } else {
+      const interfaceWrapper = interfaces.getInterfaceWrapper("HTMLElement");
+      result = interfaceWrapper.createImpl(_globalObject, [], {
+        ownerDocument: document,
+        localName,
+        namespace: HTML_NS,
+        prefix,
+        ceState: "undefined",
+        ceDefinition: null,
+        isValue: null
+      });
+
+      enqueueCEUpgradeReaction(result, definition);
+    }
+  } else {
+    let elementInterface;
+
+    switch (namespace) {
+      case HTML_NS:
+        elementInterface = getHTMLElementInterface(localName);
+        break;
+
+      case SVG_NS:
+        elementInterface = getSVGInterface(localName);
+        break;
+
+      default:
+        elementInterface = interfaces.getInterfaceWrapper("Element");
+        break;
+    }
+
+    result = elementInterface.createImpl(_globalObject, [], {
+      ownerDocument: document,
+      localName,
+      namespace,
+      prefix,
+      ceState: "uncustomized",
+      ceDefinition: null,
+      isValue
+    });
+
+    if (namespace === HTML_NS && (isValidCustomElementName(localName) || isValue !== null)) {
+      result._ceState = "undefined";
+    }
+  }
+
+  return result;
+}
+
+// https://dom.spec.whatwg.org/#internal-createelementns-steps
+function internalCreateElementNSSteps(document, namespace, qualifiedName, options) {
+  const extracted = validateAndExtract(document._globalObject, namespace, qualifiedName);
+
+  let isValue = null;
+  if (options && options.is !== undefined) {
+    isValue = options.is;
+  }
+
+  return createElement(
+    document,
+    extracted.localName,
+    extracted.namespace,
+    extracted.prefix,
+    isValue,
+    true
+  );
+}
+
+module.exports = {
+  createElement,
+  internalCreateElementNSSteps,
+
+  getValidTagNames,
+  getHTMLElementInterface
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/create-event-accessor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,188 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const ErrorEvent = require("../generated/ErrorEvent");
+const EventHandlerNonNull = require("../generated/EventHandlerNonNull.js");
+const OnBeforeUnloadEventHandlerNonNull = require("../generated/OnBeforeUnloadEventHandlerNonNull.js");
+const OnErrorEventHandlerNonNull = require("../generated/OnErrorEventHandlerNonNull.js");
+const reportException = require("./runtime-script-errors");
+
+exports.appendHandler = (el, eventName) => {
+  // tryImplForWrapper() is currently required due to use in Window.js
+  idlUtils.tryImplForWrapper(el).addEventListener(eventName, event => {
+    // https://html.spec.whatwg.org/#the-event-handler-processing-algorithm
+    const callback = exports.getCurrentEventHandlerValue(el, eventName);
+    if (callback === null) {
+      return;
+    }
+
+    const specialError = ErrorEvent.isImpl(event) && event.type === "error" &&
+      event.currentTarget.constructor.name === "Window";
+
+    let returnValue = null;
+    // https://heycam.github.io/webidl/#es-invoking-callback-functions
+    if (typeof callback === "function") {
+      if (specialError) {
+        returnValue = callback.call(
+          event.currentTarget,
+          event.message,
+          event.filename,
+          event.lineno,
+          event.colno,
+          event.error
+        );
+      } else {
+        returnValue = callback.call(event.currentTarget, event);
+      }
+    }
+
+    // TODO: we don't implement BeforeUnloadEvent so we can't brand-check here
+    if (event.type === "beforeunload") {
+      if (returnValue !== null) {
+        event._canceledFlag = true;
+        if (event.returnValue === "") {
+          event.returnValue = returnValue;
+        }
+      }
+    } else if (specialError) {
+      if (returnValue === true) {
+        event._canceledFlag = true;
+      }
+    } else if (returnValue === false) {
+      event._canceledFlag = true;
+    }
+  });
+};
+
+// "Simple" in this case means "no content attributes involved"
+exports.setupForSimpleEventAccessors = (prototype, events) => {
+  prototype._getEventHandlerFor = function (event) {
+    return this._eventHandlers ? this._eventHandlers[event] : undefined;
+  };
+
+  prototype._setEventHandlerFor = function (event, handler) {
+    if (!this._registeredHandlers) {
+      this._registeredHandlers = new Set();
+      this._eventHandlers = Object.create(null);
+    }
+
+    if (!this._registeredHandlers.has(event) && handler !== null) {
+      this._registeredHandlers.add(event);
+      exports.appendHandler(this, event);
+    }
+    this._eventHandlers[event] = handler;
+  };
+
+  for (const event of events) {
+    exports.createEventAccessor(prototype, event);
+  }
+};
+
+// https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler
+exports.getCurrentEventHandlerValue = (target, event) => {
+  const value = target._getEventHandlerFor(event);
+  if (!value) {
+    return null;
+  }
+
+  if (value.body !== undefined) {
+    let element, document, fn;
+    if (target.constructor.name === "Window") {
+      element = null;
+      document = idlUtils.implForWrapper(target.document);
+    } else {
+      element = target;
+      document = element.ownerDocument;
+    }
+    const { body } = value;
+
+    const formOwner = element !== null && element.form ? element.form : null;
+    const window = target.constructor.name === "Window" && target._document ? target : document.defaultView;
+
+    try {
+      // eslint-disable-next-line no-new-func
+      Function(body); // properly error out on syntax errors
+      // Note: this won't execute body; that would require `Function(body)()`.
+    } catch (e) {
+      if (window) {
+        reportException(window, e);
+      }
+      target._setEventHandlerFor(event, null);
+      return null;
+    }
+
+    // Note: the with (window) { } is not necessary in Node, but is necessary in a browserified environment.
+
+    const createFunction = document.defaultView.Function;
+    if (event === "error" && element === null) {
+      const sourceURL = document ? `\n//# sourceURL=${document.URL}` : "";
+
+      fn = createFunction(`\
+with (arguments[0]) { return function onerror(event, source, lineno, colno, error) {
+${body}
+}; }${sourceURL}`)(window);
+
+      fn = OnErrorEventHandlerNonNull.convert(fn);
+    } else {
+      const calls = [];
+      if (element !== null) {
+        calls.push(idlUtils.wrapperForImpl(document));
+      }
+
+      if (formOwner !== null) {
+        calls.push(idlUtils.wrapperForImpl(formOwner));
+      }
+
+      if (element !== null) {
+        calls.push(idlUtils.wrapperForImpl(element));
+      }
+
+      let wrapperBody = `\
+with (arguments[0]) { return function on${event}(event) {
+${body}
+}; }`;
+
+      // eslint-disable-next-line no-unused-vars
+      for (const call of calls) {
+        wrapperBody = `\
+with (arguments[0]) { return function () {
+${wrapperBody}
+}; }`;
+      }
+
+      if (document) {
+        wrapperBody += `\n//# sourceURL=${document.URL}`;
+      }
+
+      fn = createFunction(wrapperBody)(window);
+      for (const call of calls) {
+        fn = fn(call);
+      }
+
+      if (event === "beforeunload") {
+        fn = OnBeforeUnloadEventHandlerNonNull.convert(fn);
+      } else {
+        fn = EventHandlerNonNull.convert(fn);
+      }
+    }
+
+    target._setEventHandlerFor(event, fn);
+  }
+
+  return target._getEventHandlerFor(event);
+};
+
+// https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-idl-attributes
+// TODO: Consider replacing this with `[ReflectEvent]`
+exports.createEventAccessor = (obj, event) => {
+  Object.defineProperty(obj, "on" + event, {
+    configurable: true,
+    enumerable: true,
+    get() {
+      return exports.getCurrentEventHandlerValue(this, event);
+    },
+    set(val) {
+      this._setEventHandlerFor(event, val);
+    }
+  });
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/custom-elements.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/custom-elements.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/custom-elements.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,270 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const isPotentialCustomElementName = require("is-potential-custom-element-name");
+
+const NODE_TYPE = require("../node-type");
+const { HTML_NS } = require("./namespaces");
+const { shadowIncludingRoot } = require("./shadow-dom");
+const reportException = require("./runtime-script-errors");
+
+const { implForWrapper, wrapperForImpl } = require("../generated/utils");
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions-stack
+class CEReactionsStack {
+  constructor() {
+    this._stack = [];
+
+    // https://html.spec.whatwg.org/multipage/custom-elements.html#backup-element-queue
+    this.backupElementQueue = [];
+
+    // https://html.spec.whatwg.org/multipage/custom-elements.html#processing-the-backup-element-queue
+    this.processingBackupElementQueue = false;
+  }
+
+  push(elementQueue) {
+    this._stack.push(elementQueue);
+  }
+
+  pop() {
+    return this._stack.pop();
+  }
+
+  get currentElementQueue() {
+    const { _stack } = this;
+    return _stack[_stack.length - 1];
+  }
+
+  isEmpty() {
+    return this._stack.length === 0;
+  }
+}
+
+// In theory separate cross-origin Windows created by separate JSDOM instances could have separate stacks. But, we would
+// need to implement the whole agent architecture. Which is kind of questionable given that we don't run our Windows in
+// their own separate threads, which is what agents are meant to represent.
+const customElementReactionsStack = new CEReactionsStack();
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
+function ceReactionsPreSteps() {
+  customElementReactionsStack.push([]);
+}
+function ceReactionsPostSteps() {
+  const queue = customElementReactionsStack.pop();
+  invokeCEReactions(queue);
+}
+
+const RESTRICTED_CUSTOM_ELEMENT_NAME = new Set([
+  "annotation-xml",
+  "color-profile",
+  "font-face",
+  "font-face-src",
+  "font-face-uri",
+  "font-face-format",
+  "font-face-name",
+  "missing-glyph"
+]);
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
+function isValidCustomElementName(name) {
+  if (RESTRICTED_CUSTOM_ELEMENT_NAME.has(name)) {
+    return false;
+  }
+
+  return isPotentialCustomElementName(name);
+}
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#concept-upgrade-an-element
+function upgradeElement(definition, element) {
+  if (element._ceState !== "undefined" || element._ceState === "uncustomized") {
+    return;
+  }
+
+  element._ceDefinition = definition;
+  element._ceState = "failed";
+
+  for (const attribute of element._attributeList) {
+    const { _localName, _namespace, _value } = attribute;
+    enqueueCECallbackReaction(element, "attributeChangedCallback", [_localName, null, _value, _namespace]);
+  }
+
+  if (shadowIncludingRoot(element).nodeType === NODE_TYPE.DOCUMENT_NODE) {
+    enqueueCECallbackReaction(element, "connectedCallback", []);
+  }
+
+  definition.constructionStack.push(element);
+
+  const { constructionStack, constructor: C } = definition;
+
+  let constructionError;
+  try {
+    if (definition.disableShadow === true && element._shadowRoot !== null) {
+      throw DOMException.create(element._globalObject, [
+        "Can't upgrade a custom element with a shadow root if shadow is disabled",
+        "NotSupportedError"
+      ]);
+    }
+
+    const constructionResult = C.construct();
+    const constructionResultImpl = implForWrapper(constructionResult);
+
+    if (constructionResultImpl !== element) {
+      throw new TypeError("Invalid custom element constructor return value");
+    }
+  } catch (error) {
+    constructionError = error;
+  }
+
+  constructionStack.pop();
+
+  if (constructionError !== undefined) {
+    element._ceDefinition = null;
+    element._ceReactionQueue = [];
+
+    throw constructionError;
+  }
+
+  element._ceState = "custom";
+}
+
+// https://html.spec.whatwg.org/#concept-try-upgrade
+function tryUpgradeElement(element) {
+  const { _ownerDocument, _namespaceURI, _localName, _isValue } = element;
+  const definition = lookupCEDefinition(_ownerDocument, _namespaceURI, _localName, _isValue);
+
+  if (definition !== null) {
+    enqueueCEUpgradeReaction(element, definition);
+  }
+}
+
+// https://html.spec.whatwg.org/#look-up-a-custom-element-definition
+function lookupCEDefinition(document, namespace, localName, isValue) {
+  const definition = null;
+
+  if (namespace !== HTML_NS) {
+    return definition;
+  }
+
+  if (!document._defaultView) {
+    return definition;
+  }
+
+  const registry = implForWrapper(document._globalObject.customElements);
+
+  const definitionByName = registry._customElementDefinitions.find(def => {
+    return def.name === def.localName && def.localName === localName;
+  });
+  if (definitionByName !== undefined) {
+    return definitionByName;
+  }
+
+  const definitionByIs = registry._customElementDefinitions.find(def => {
+    return def.name === isValue && def.localName === localName;
+  });
+  if (definitionByIs !== undefined) {
+    return definitionByIs;
+  }
+
+  return definition;
+}
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#invoke-custom-element-reactions
+function invokeCEReactions(elementQueue) {
+  while (elementQueue.length > 0) {
+    const element = elementQueue.shift();
+
+    const reactions = element._ceReactionQueue;
+
+    try {
+      while (reactions.length > 0) {
+        const reaction = reactions.shift();
+
+        switch (reaction.type) {
+          case "upgrade":
+            upgradeElement(reaction.definition, element);
+            break;
+
+          case "callback":
+            reaction.callback.apply(wrapperForImpl(element), reaction.args);
+            break;
+        }
+      }
+    } catch (error) {
+      reportException(element._globalObject, error);
+    }
+  }
+}
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#enqueue-an-element-on-the-appropriate-element-queue
+function enqueueElementOnAppropriateElementQueue(element) {
+  if (customElementReactionsStack.isEmpty()) {
+    customElementReactionsStack.backupElementQueue.push(element);
+
+    if (customElementReactionsStack.processingBackupElementQueue) {
+      return;
+    }
+
+    customElementReactionsStack.processingBackupElementQueue = true;
+
+    Promise.resolve().then(() => {
+      const elementQueue = customElementReactionsStack.backupElementQueue;
+      invokeCEReactions(elementQueue);
+
+      customElementReactionsStack.processingBackupElementQueue = false;
+    });
+  } else {
+    customElementReactionsStack.currentElementQueue.push(element);
+  }
+}
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#enqueue-a-custom-element-callback-reaction
+function enqueueCECallbackReaction(element, callbackName, args) {
+  const { _ceDefinition: { lifecycleCallbacks, observedAttributes } } = element;
+
+  const callback = lifecycleCallbacks[callbackName];
+  if (callback === null) {
+    return;
+  }
+
+  if (callbackName === "attributeChangedCallback") {
+    const attributeName = args[0];
+    if (!observedAttributes.includes(attributeName)) {
+      return;
+    }
+  }
+
+  element._ceReactionQueue.push({
+    type: "callback",
+    callback,
+    args
+  });
+
+  enqueueElementOnAppropriateElementQueue(element);
+}
+
+// https://html.spec.whatwg.org/#enqueue-a-custom-element-upgrade-reaction
+function enqueueCEUpgradeReaction(element, definition) {
+  element._ceReactionQueue.push({
+    type: "upgrade",
+    definition
+  });
+
+  enqueueElementOnAppropriateElementQueue(element);
+}
+
+module.exports = {
+  customElementReactionsStack,
+
+  ceReactionsPreSteps,
+  ceReactionsPostSteps,
+
+  isValidCustomElementName,
+
+  upgradeElement,
+  tryUpgradeElement,
+
+  lookupCEDefinition,
+  enqueueCEUpgradeReaction,
+  enqueueCECallbackReaction,
+  invokeCEReactions
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/dates-and-times.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/dates-and-times.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/dates-and-times.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,270 @@
+"use strict";
+
+function isLeapYear(year) {
+  return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0);
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#number-of-days-in-month-month-of-year-year
+const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+function numberOfDaysInMonthOfYear(month, year) {
+  if (month === 2 && isLeapYear(year)) {
+    return 29;
+  }
+  return daysInMonth[month - 1];
+}
+
+const monthRe = /^([0-9]{4,})-([0-9]{2})$/;
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-month-string
+function parseMonthString(str) {
+  const matches = monthRe.exec(str);
+  if (!matches) {
+    return null;
+  }
+  const year = Number(matches[1]);
+  if (year <= 0) {
+    return null;
+  }
+  const month = Number(matches[2]);
+  if (month < 1 || month > 12) {
+    return null;
+  }
+  return { year, month };
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-month-string
+function isValidMonthString(str) {
+  return parseMonthString(str) !== null;
+}
+function serializeMonth({ year, month }) {
+  const yearStr = `${year}`.padStart(4, "0");
+  const monthStr = `${month}`.padStart(2, "0");
+  return `${yearStr}-${monthStr}`;
+}
+
+const dateRe = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/;
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-date-string
+function parseDateString(str) {
+  const matches = dateRe.exec(str);
+  if (!matches) {
+    return null;
+  }
+  const year = Number(matches[1]);
+  if (year <= 0) {
+    return null;
+  }
+  const month = Number(matches[2]);
+  if (month < 1 || month > 12) {
+    return null;
+  }
+  const day = Number(matches[3]);
+  if (day < 1 || day > numberOfDaysInMonthOfYear(month, year)) {
+    return null;
+  }
+  return { year, month, day };
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
+function isValidDateString(str) {
+  return parseDateString(str) !== null;
+}
+function serializeDate(date) {
+  const dayStr = `${date.day}`.padStart(2, "0");
+  return `${serializeMonth(date)}-${dayStr}`;
+}
+
+const yearlessDateRe = /^(?:--)?([0-9]{2})-([0-9]{2})$/;
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-yearless-date-string
+function parseYearlessDateString(str) {
+  const matches = yearlessDateRe.exec(str);
+  if (!matches) {
+    return null;
+  }
+  const month = Number(matches[1]);
+  if (month < 1 || month > 12) {
+    return null;
+  }
+  const day = Number(matches[2]);
+  if (day < 1 || day > numberOfDaysInMonthOfYear(month, 4)) {
+    return null;
+  }
+  return { month, day };
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-yearless-date-string
+function isValidYearlessDateString(str) {
+  return parseYearlessDateString(str) !== null;
+}
+function serializeYearlessDate({ month, day }) {
+  const monthStr = `${month}`.padStart(2, "0");
+  const dayStr = `${day}`.padStart(2, "0");
+  return `${monthStr}-${dayStr}`;
+}
+
+const timeRe = /^([0-9]{2}):([0-9]{2})(?::([0-9]{2}(?:\.([0-9]{1,3}))?))?$/;
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-time-string
+function parseTimeString(str) {
+  const matches = timeRe.exec(str);
+  if (!matches) {
+    return null;
+  }
+  const hour = Number(matches[1]);
+  if (hour < 0 || hour > 23) {
+    return null;
+  }
+  const minute = Number(matches[2]);
+  if (minute < 0 || minute > 59) {
+    return null;
+  }
+  const second = matches[3] !== undefined ? Math.trunc(Number(matches[3])) : 0;
+  if (second < 0 || second >= 60) {
+    return null;
+  }
+  const millisecond = matches[4] !== undefined ? Number(matches[4]) : 0;
+  return { hour, minute, second, millisecond };
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-time-string
+function isValidTimeString(str) {
+  return parseTimeString(str) !== null;
+}
+
+function serializeTime({ hour, minute, second, millisecond }) {
+  const hourStr = `${hour}`.padStart(2, "0");
+  const minuteStr = `${minute}`.padStart(2, "0");
+  if (second === 0 && millisecond === 0) {
+    return `${hourStr}:${minuteStr}`;
+  }
+  const secondStr = `${second}`.padStart(2, "0");
+  const millisecondStr = `${millisecond}`.padStart(3, "0");
+  return `${hourStr}:${minuteStr}:${secondStr}.${millisecondStr}`;
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-local-date-and-time-string
+function parseLocalDateAndTimeString(str, normalized = false) {
+  let separatorIdx = str.indexOf("T");
+  if (separatorIdx < 0 && !normalized) {
+    separatorIdx = str.indexOf(" ");
+  }
+  if (separatorIdx < 0) {
+    return null;
+  }
+  const date = parseDateString(str.slice(0, separatorIdx));
+  if (date === null) {
+    return null;
+  }
+  const time = parseTimeString(str.slice(separatorIdx + 1));
+  if (time === null) {
+    return null;
+  }
+  return { date, time };
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-local-date-and-time-string
+function isValidLocalDateAndTimeString(str) {
+  return parseLocalDateAndTimeString(str) !== null;
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-normalised-local-date-and-time-string
+function isValidNormalizedLocalDateAndTimeString(str) {
+  return parseLocalDateAndTimeString(str, true) !== null;
+}
+function serializeNormalizedDateAndTime({ date, time }) {
+  return `${serializeDate(date)}T${serializeTime(time)}`;
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#week-number-of-the-last-day
+// https://stackoverflow.com/a/18538272/1937836
+function weekNumberOfLastDay(year) {
+  const jan1 = new Date(year, 0);
+  return jan1.getDay() === 4 || (isLeapYear(year) && jan1.getDay() === 3) ? 53 : 52;
+}
+
+const weekRe = /^([0-9]{4,5})-W([0-9]{2})$/;
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#parse-a-week-string
+function parseWeekString(str) {
+  const matches = weekRe.exec(str);
+  if (!matches) {
+    return null;
+  }
+  const year = Number(matches[1]);
+  if (year <= 0) {
+    return null;
+  }
+  const week = Number(matches[2]);
+  if (week < 1 || week > weekNumberOfLastDay(year)) {
+    return null;
+  }
+  return { year, week };
+}
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-week-string
+function isValidWeekString(str) {
+  return parseWeekString(str) !== null;
+}
+function serializeWeek({ year, week }) {
+  const yearStr = `${year}`.padStart(4, "0");
+  const weekStr = `${week}`.padStart(2, "0");
+  return `${yearStr}-W${weekStr}`;
+}
+
+// https://stackoverflow.com/a/6117889
+function parseDateAsWeek(originalDate) {
+  const dayInSeconds = 86400000;
+  // Copy date so don't modify original
+  const date = new Date(Date.UTC(originalDate.getUTCFullYear(), originalDate.getUTCMonth(), originalDate.getUTCDate()));
+  // Set to nearest Thursday: current date + 4 - current day number
+  // Make Sunday's day number 7
+  date.setUTCDate(date.getUTCDate() + 4 - (date.getUTCDay() || 7));
+  // Get first day of year
+  const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
+  // Calculate full weeks to nearest Thursday
+  const week = Math.ceil((((date - yearStart) / dayInSeconds) + 1) / 7);
+
+  return { year: date.getUTCFullYear(), week };
+}
+
+function isDate(obj) {
+  try {
+    Date.prototype.valueOf.call(obj);
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+module.exports = {
+  isDate,
+  numberOfDaysInMonthOfYear,
+
+  parseMonthString,
+  isValidMonthString,
+  serializeMonth,
+
+  parseDateString,
+  isValidDateString,
+  serializeDate,
+
+  parseYearlessDateString,
+  isValidYearlessDateString,
+  serializeYearlessDate,
+
+  parseTimeString,
+  isValidTimeString,
+  serializeTime,
+
+  parseLocalDateAndTimeString,
+  isValidLocalDateAndTimeString,
+  isValidNormalizedLocalDateAndTimeString,
+  serializeNormalizedDateAndTime,
+
+  parseDateAsWeek,
+  weekNumberOfLastDay,
+  parseWeekString,
+  isValidWeekString,
+  serializeWeek
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/details.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/details.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/details.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+const { firstChildWithLocalName } = require("./traversal");
+const { HTML_NS } = require("./namespaces");
+
+// https://html.spec.whatwg.org/multipage/interactive-elements.html#summary-for-its-parent-details
+exports.isSummaryForParentDetails = summaryElement => {
+  const parent = summaryElement.parentNode;
+  if (parent === null) {
+    return false;
+  }
+  if (parent._localName !== "details" || parent._namespaceURI !== HTML_NS) {
+    return false;
+  }
+  return firstChildWithLocalName(parent, "summary") === summaryElement;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/document-base-url.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/document-base-url.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/document-base-url.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,54 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const { implForWrapper } = require("../generated/utils");
+
+exports.documentBaseURL = document => {
+  // https://html.spec.whatwg.org/multipage/infrastructure.html#document-base-url
+
+  const firstBase = document.querySelector("base[href]");
+  const fallbackBaseURL = exports.fallbackBaseURL(document);
+
+  if (firstBase === null) {
+    return fallbackBaseURL;
+  }
+
+  return frozenBaseURL(firstBase, fallbackBaseURL);
+};
+
+exports.documentBaseURLSerialized = document => {
+  return whatwgURL.serializeURL(exports.documentBaseURL(document));
+};
+
+exports.fallbackBaseURL = document => {
+  // https://html.spec.whatwg.org/multipage/infrastructure.html#fallback-base-url
+
+  // Unimplemented: <iframe srcdoc>
+
+  if (document.URL === "about:blank" && document._defaultView &&
+      document._defaultView._parent !== document._defaultView) {
+    const parentDocument = implForWrapper(document._defaultView._parent._document);
+    return exports.documentBaseURL(parentDocument);
+  }
+
+  return document._URL;
+};
+
+exports.parseURLToResultingURLRecord = (url, document) => {
+  // https://html.spec.whatwg.org/#resolve-a-url
+
+  // Encoding stuff ignored; always UTF-8 for us, for now.
+
+  const baseURL = exports.documentBaseURL(document);
+
+  return whatwgURL.parseURL(url, { baseURL });
+  // This returns the resulting URL record; to get the resulting URL string, just serialize it.
+};
+
+function frozenBaseURL(baseElement, fallbackBaseURL) {
+  // https://html.spec.whatwg.org/multipage/semantics.html#frozen-base-url
+  // The spec is eager (setting the frozen base URL when things change); we are lazy (getting it when we need to)
+
+  const baseHrefAttribute = baseElement.getAttributeNS(null, "href");
+  const result = whatwgURL.parseURL(baseHrefAttribute, { baseURL: fallbackBaseURL });
+  return result === null ? fallbackBaseURL : result;
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/events.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/events.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/events.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+"use strict";
+
+const Event = require("../generated/Event");
+const { tryImplForWrapper } = require("../generated/utils");
+
+function createAnEvent(e, globalObject, eventInterface = Event, attributes = {}) {
+  return eventInterface.createImpl(
+    globalObject,
+    [e, attributes],
+    { isTrusted: attributes.isTrusted !== false }
+  );
+}
+
+function fireAnEvent(e, target, eventInterface, attributes, legacyTargetOverrideFlag) {
+  const event = createAnEvent(e, target._globalObject, eventInterface, attributes);
+
+  // tryImplForWrapper() is currently required due to use in Window.js
+  return tryImplForWrapper(target)._dispatch(event, legacyTargetOverrideFlag);
+}
+
+module.exports = {
+  createAnEvent,
+  fireAnEvent
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/focusing.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/focusing.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/focusing.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,104 @@
+"use strict";
+const FocusEvent = require("../generated/FocusEvent.js");
+const idlUtils = require("../generated/utils.js");
+const { isDisabled } = require("./form-controls.js");
+const { firstChildWithLocalName } = require("./traversal");
+const { createAnEvent } = require("./events");
+const { HTML_NS, SVG_NS } = require("./namespaces");
+const { isRenderedElement } = require("./svg/render");
+
+const focusableFormElements = new Set(["input", "select", "textarea", "button"]);
+
+// https://html.spec.whatwg.org/multipage/interaction.html#focusable-area, but also some of
+// https://html.spec.whatwg.org/multipage/interaction.html#focusing-steps and some of
+// https://svgwg.org/svg2-draft/interact.html#TermFocusable
+exports.isFocusableAreaElement = elImpl => {
+  // We implemented most of the suggested focusable elements found here:
+  // https://html.spec.whatwg.org/multipage/interaction.html#tabindex-value
+  // However, some suggested elements are not focusable in web browsers, as detailed here:
+  // https://github.com/whatwg/html/issues/5490
+  if (elImpl._namespaceURI === HTML_NS) {
+    if (!elImpl._ownerDocument._defaultView) {
+      return false;
+    }
+
+    if (!elImpl.isConnected) {
+      return false;
+    }
+
+    if (!Number.isNaN(parseInt(elImpl.getAttributeNS(null, "tabindex")))) {
+      return true;
+    }
+
+    if (elImpl._localName === "iframe") {
+      return true;
+    }
+
+    if (elImpl._localName === "a" && elImpl.hasAttributeNS(null, "href")) {
+      return true;
+    }
+
+    if (elImpl._localName === "summary" && elImpl.parentNode &&
+        elImpl.parentNode._localName === "details" &&
+        elImpl === firstChildWithLocalName(elImpl.parentNode, "summary")) {
+      return true;
+    }
+
+    if (focusableFormElements.has(elImpl._localName) && !isDisabled(elImpl)) {
+      if (elImpl._localName === "input" && elImpl.type === "hidden") {
+        return false;
+      }
+
+      return true;
+    }
+
+    if (elImpl.hasAttributeNS(null, "contenteditable")) {
+      return true;
+    }
+
+    return false;
+
+    // This does not check for a designMode Document as specified in
+    // https://html.spec.whatwg.org/multipage/interaction.html#editing-host because the designMode
+    // attribute is not implemented.
+  }
+
+  if (elImpl._namespaceURI === SVG_NS) {
+    if (!Number.isNaN(parseInt(elImpl.getAttributeNS(null, "tabindex"))) && isRenderedElement(elImpl)) {
+      return true;
+    }
+
+    if (elImpl._localName === "a" && elImpl.hasAttributeNS(null, "href")) {
+      return true;
+    }
+
+    return false;
+  }
+
+  return false;
+};
+
+// https://html.spec.whatwg.org/multipage/interaction.html#fire-a-focus-event plus the steps of
+// https://html.spec.whatwg.org/multipage/interaction.html#focus-update-steps that adjust Documents to Windows
+// It's extended with the bubbles option to also handle focusin/focusout, which are "defined" in
+// https://w3c.github.io/uievents/#event-type-focusin. See https://github.com/whatwg/html/issues/3514.
+exports.fireFocusEventWithTargetAdjustment = (name, target, relatedTarget, { bubbles = false } = {}) => {
+  if (target === null) {
+    // E.g. firing blur with nothing previously focused.
+    return;
+  }
+
+  const event = createAnEvent(name, target._globalObject, FocusEvent, {
+    bubbles,
+    composed: true,
+    relatedTarget,
+    view: target._ownerDocument._defaultView,
+    detail: 0
+  });
+
+  if (target._defaultView) {
+    target = idlUtils.implForWrapper(target._defaultView);
+  }
+
+  target._dispatch(event);
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/form-controls.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/form-controls.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/form-controls.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,306 @@
+"use strict";
+
+const {
+  isValidFloatingPointNumber,
+  isValidSimpleColor,
+  parseFloatingPointNumber,
+  stripLeadingAndTrailingASCIIWhitespace,
+  stripNewlines,
+  splitOnCommas
+} = require("./strings");
+const {
+  isValidDateString,
+  isValidMonthString,
+  isValidTimeString,
+  isValidWeekString,
+  parseLocalDateAndTimeString,
+  serializeNormalizedDateAndTime
+} = require("./dates-and-times");
+const whatwgURL = require("whatwg-url");
+
+const NodeList = require("../generated/NodeList");
+const { domSymbolTree } = require("./internal-constants");
+const { closest, firstChildWithLocalName } = require("./traversal");
+const NODE_TYPE = require("../node-type");
+const { HTML_NS } = require("./namespaces");
+
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled
+exports.isDisabled = formControl => {
+  if (formControl.localName === "button" || formControl.localName === "input" || formControl.localName === "select" ||
+      formControl.localName === "textarea") {
+    if (formControl.hasAttributeNS(null, "disabled")) {
+      return true;
+    }
+  }
+
+  let e = formControl.parentNode;
+  while (e) {
+    if (e.localName === "fieldset" && e.hasAttributeNS(null, "disabled")) {
+      const firstLegendElementChild = firstChildWithLocalName(e, "legend");
+      if (!firstLegendElementChild || !firstLegendElementChild.contains(formControl)) {
+        return true;
+      }
+    }
+    e = e.parentNode;
+  }
+
+  return false;
+};
+
+// https://html.spec.whatwg.org/multipage/forms.html#category-listed
+const listedElements = new Set(["button", "fieldset", "input", "object", "output", "select", "textarea"]);
+exports.isListed = formControl => listedElements.has(formControl._localName) && formControl.namespaceURI === HTML_NS;
+
+// https://html.spec.whatwg.org/multipage/forms.html#category-submit
+const submittableElements = new Set(["button", "input", "object", "select", "textarea"]);
+exports.isSubmittable = formControl => {
+  return submittableElements.has(formControl._localName) && formControl.namespaceURI === HTML_NS;
+};
+
+// https://html.spec.whatwg.org/multipage/forms.html#concept-submit-button
+const submitButtonInputTypes = new Set(["submit", "image"]);
+exports.isSubmitButton = formControl => {
+  return ((formControl._localName === "input" && submitButtonInputTypes.has(formControl.type)) ||
+          (formControl._localName === "button" && formControl.type === "submit")) &&
+         formControl.namespaceURI === HTML_NS;
+};
+
+// https://html.spec.whatwg.org/multipage/forms.html#concept-button
+const buttonInputTypes = new Set([...submitButtonInputTypes, "reset", "button"]);
+exports.isButton = formControl => {
+  return ((formControl._localName === "input" && buttonInputTypes.has(formControl.type)) ||
+          formControl._localName === "button") &&
+         formControl.namespaceURI === HTML_NS;
+};
+
+// https://html.spec.whatwg.org/multipage/dom.html#interactive-content-2
+exports.isInteractiveContent = node => {
+  if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+    return false;
+  }
+  if (node.namespaceURI !== HTML_NS) {
+    return false;
+  }
+  if (node.hasAttributeNS(null, "tabindex")) {
+    return true;
+  }
+  switch (node.localName) {
+    case "a":
+      return node.hasAttributeNS(null, "href");
+
+    case "audio":
+    case "video":
+      return node.hasAttributeNS(null, "controls");
+
+    case "img":
+    case "object":
+      return node.hasAttributeNS(null, "usemap");
+
+    case "input":
+      return node.type !== "hidden";
+
+    case "button":
+    case "details":
+    case "embed":
+    case "iframe":
+    case "label":
+    case "select":
+    case "textarea":
+      return true;
+  }
+
+  return false;
+};
+
+// https://html.spec.whatwg.org/multipage/forms.html#category-label
+exports.isLabelable = node => {
+  if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+    return false;
+  }
+  if (node.namespaceURI !== HTML_NS) {
+    return false;
+  }
+  switch (node.localName) {
+    case "button":
+    case "meter":
+    case "output":
+    case "progress":
+    case "select":
+    case "textarea":
+      return true;
+
+    case "input":
+      return node.type !== "hidden";
+  }
+
+  return false;
+};
+
+exports.getLabelsForLabelable = labelable => {
+  if (!exports.isLabelable(labelable)) {
+    return null;
+  }
+  if (!labelable._labels) {
+    const root = labelable.getRootNode({});
+    labelable._labels = NodeList.create(root._globalObject, [], {
+      element: root,
+      query: () => {
+        const nodes = [];
+        for (const descendant of domSymbolTree.treeIterator(root)) {
+          if (descendant.control === labelable) {
+            nodes.push(descendant);
+          }
+        }
+        return nodes;
+      }
+    });
+  }
+  return labelable._labels;
+};
+
+// https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
+exports.isValidEmailAddress = (emailAddress, multiple = false) => {
+  const emailAddressRegExp = new RegExp("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9]" +
+    "(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}" +
+    "[a-zA-Z0-9])?)*$");
+  // A valid e-mail address list is a set of comma-separated tokens, where each token is itself
+  // a valid e - mail address.To obtain the list of tokens from a valid e - mail address list,
+  // an implementation must split the string on commas.
+  if (multiple) {
+    return splitOnCommas(emailAddress).every(value => emailAddressRegExp.test(value));
+  }
+  return emailAddressRegExp.test(emailAddress);
+};
+
+exports.isValidAbsoluteURL = url => {
+  return whatwgURL.parseURL(url) !== null;
+};
+
+exports.sanitizeValueByType = (input, val) => {
+  switch (input.type.toLowerCase()) {
+    case "password":
+    case "search":
+    case "tel":
+    case "text":
+      val = stripNewlines(val);
+      break;
+
+    case "color":
+      // https://html.spec.whatwg.org/multipage/forms.html#color-state-(type=color):value-sanitization-algorithm
+      val = isValidSimpleColor(val) ? val.toLowerCase() : "#000000";
+      break;
+
+    case "date":
+      // https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date):value-sanitization-algorithm
+      if (!isValidDateString(val)) {
+        val = "";
+      }
+      break;
+
+    case "datetime-local": {
+      // https://html.spec.whatwg.org/multipage/input.html#local-date-and-time-state-(type=datetime-local):value-sanitization-algorithm
+      const dateAndTime = parseLocalDateAndTimeString(val);
+      val = dateAndTime !== null ? serializeNormalizedDateAndTime(dateAndTime) : "";
+      break;
+    }
+
+    case "email":
+      // https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email):value-sanitization-algorithm
+      // https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email):value-sanitization-algorithm-2
+      if (input.hasAttributeNS(null, "multiple")) {
+        val = val.split(",").map(token => stripLeadingAndTrailingASCIIWhitespace(token)).join(",");
+      } else {
+        val = stripNewlines(val);
+        val = stripLeadingAndTrailingASCIIWhitespace(val);
+      }
+      break;
+
+    case "month":
+      // https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):value-sanitization-algorithm
+      if (!isValidMonthString(val)) {
+        val = "";
+      }
+      break;
+
+    case "number":
+      // https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number):value-sanitization-algorithm
+      // TODO: using parseFloatingPointNumber in addition to isValidFloatingPointNumber to pass number.html WPT.
+      // Possible spec bug.
+      if (!isValidFloatingPointNumber(val) || parseFloatingPointNumber(val) === null) {
+        val = "";
+      }
+      break;
+
+    case "range":
+      // https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range):value-sanitization-algorithm
+      // TODO: using parseFloatingPointNumber in addition to isValidFloatingPointNumber to pass number.html WPT.
+      // Possible spec bug.
+      if (!isValidFloatingPointNumber(val) || parseFloatingPointNumber(val) === null) {
+        const minimum = input._minimum;
+        const maximum = input._maximum;
+        const defaultValue = maximum < minimum ? minimum : (minimum + maximum) / 2;
+        val = `${defaultValue}`;
+      } else if (val < input._minimum) {
+        val = `${input._minimum}`;
+      } else if (val > input._maximum) {
+        val = `${input._maximum}`;
+      }
+      break;
+
+    case "time":
+      // https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):value-sanitization-algorithm
+      if (!isValidTimeString(val)) {
+        val = "";
+      }
+      break;
+
+    case "url":
+      // https://html.spec.whatwg.org/multipage/forms.html#url-state-(type=url):value-sanitization-algorithm
+      val = stripNewlines(val);
+      val = stripLeadingAndTrailingASCIIWhitespace(val);
+      break;
+
+    case "week":
+      // https://html.spec.whatwg.org/multipage/input.html#week-state-(type=week):value-sanitization-algorithm
+      if (!isValidWeekString(val)) {
+        val = "";
+      }
+  }
+
+  return val;
+};
+
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-owner
+// TODO: The spec describes an imperative process for assigning/resetting an element's form
+// owner based on activities involving form-associated elements. This simpler implementation
+// instead calculates the current form owner only when the property is accessed. This is not
+// sufficient to pass all the web platform tests, but is good enough for most purposes. We
+// should eventually update it to use the correct version, though. See
+// https://github.com/whatwg/html/issues/4050 for some discussion.
+
+exports.formOwner = formControl => {
+  const formAttr = formControl.getAttributeNS(null, "form");
+  if (formAttr === "") {
+    return null;
+  }
+  if (formAttr === null) {
+    return closest(formControl, "form");
+  }
+
+  const root = formControl.getRootNode({});
+  let firstElementWithId;
+  for (const descendant of domSymbolTree.treeIterator(root)) {
+    if (descendant.nodeType === NODE_TYPE.ELEMENT_NODE &&
+      descendant.getAttributeNS(null, "id") === formAttr) {
+      firstElementWithId = descendant;
+      break;
+    }
+  }
+
+  if (firstElementWithId &&
+    firstElementWithId.namespaceURI === HTML_NS &&
+    firstElementWithId.localName === "form") {
+    return firstElementWithId;
+  }
+  return null;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/html-constructor.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/html-constructor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/html-constructor.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,78 @@
+"use strict";
+
+const { HTML_NS } = require("./namespaces");
+const { createElement, getValidTagNames } = require("./create-element");
+
+const { implForWrapper, wrapperForImpl } = require("../generated/utils");
+
+// https://html.spec.whatwg.org/multipage/custom-elements.html#concept-already-constructed-marker
+const ALREADY_CONSTRUCTED_MARKER = Symbol("already-constructed-marker");
+
+// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
+function HTMLConstructor(globalObject, constructorName, newTarget) {
+  const registry = implForWrapper(globalObject.customElements);
+  if (newTarget === HTMLConstructor) {
+    throw new TypeError("Invalid constructor");
+  }
+
+  const definition = registry._customElementDefinitions.find(entry => entry.objectReference === newTarget);
+  if (definition === undefined) {
+    throw new TypeError("Invalid constructor, the constructor is not part of the custom element registry");
+  }
+
+  let isValue = null;
+
+  if (definition.localName === definition.name) {
+    if (constructorName !== "HTMLElement") {
+      throw new TypeError("Invalid constructor, autonomous custom element should extend from HTMLElement");
+    }
+  } else {
+    const validLocalNames = getValidTagNames(HTML_NS, constructorName);
+    if (!validLocalNames.includes(definition.localName)) {
+      throw new TypeError(`${definition.localName} is not valid local name for ${constructorName}`);
+    }
+
+    isValue = definition.name;
+  }
+
+  let { prototype } = newTarget;
+
+  if (prototype === null || typeof prototype !== "object") {
+    // The following line deviates from the specification. The HTMLElement prototype should be retrieved from the realm
+    // associated with the "new.target". Because it is impossible to get such information in jsdom, we fallback to the
+    // HTMLElement prototype associated with the current object.
+    prototype = globalObject.HTMLElement.prototype;
+  }
+
+  if (definition.constructionStack.length === 0) {
+    const documentImpl = implForWrapper(globalObject.document);
+
+    const elementImpl = createElement(documentImpl, definition.localName, HTML_NS);
+
+    const element = wrapperForImpl(elementImpl);
+    Object.setPrototypeOf(element, prototype);
+
+    elementImpl._ceState = "custom";
+    elementImpl._ceDefinition = definition;
+    elementImpl._isValue = isValue;
+
+    return element;
+  }
+
+  const elementImpl = definition.constructionStack[definition.constructionStack.length - 1];
+  const element = wrapperForImpl(elementImpl);
+
+  if (elementImpl === ALREADY_CONSTRUCTED_MARKER) {
+    throw new TypeError("This instance is already constructed");
+  }
+
+  Object.setPrototypeOf(element, prototype);
+
+  definition.constructionStack[definition.constructionStack.length - 1] = ALREADY_CONSTRUCTED_MARKER;
+
+  return element;
+}
+
+module.exports = {
+  HTMLConstructor
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/http-request.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/http-request.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/http-request.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,254 @@
+"use strict";
+const http = require("http");
+const https = require("https");
+const { Writable } = require("stream");
+const zlib = require("zlib");
+
+const ver = process.version.replace("v", "").split(".");
+const majorNodeVersion = Number.parseInt(ver[0]);
+
+function abortRequest(clientRequest) {
+  // clientRequest.destroy breaks the test suite for versions 10 and 12,
+  // hence the version check
+  if (majorNodeVersion > 13) {
+    clientRequest.destroy();
+  } else {
+    clientRequest.abort();
+  }
+  clientRequest.removeAllListeners();
+  clientRequest.on("error", () => {});
+}
+
+module.exports = class Request extends Writable {
+  constructor(url, clientOptions, requestOptions) {
+    super();
+    Object.assign(this, clientOptions);
+    this.currentURL = url;
+    this._requestOptions = requestOptions;
+    this.headers = requestOptions.headers;
+    this._ended = false;
+    this._redirectCount = 0;
+    this._requestBodyBuffers = [];
+    this._bufferIndex = 0;
+    this._performRequest();
+  }
+
+  abort() {
+    abortRequest(this._currentRequest);
+    this.emit("abort");
+    this.removeAllListeners();
+  }
+
+  pipeRequest(form) {
+    form.pipe(this._currentRequest);
+  }
+
+  write(data, encoding) {
+    if (data.length > 0) {
+      this._requestBodyBuffers.push({ data, encoding });
+      this._currentRequest.write(data, encoding);
+    }
+  }
+
+  end() {
+    this.emit("request", this._currentRequest);
+    this._ended = true;
+    this._currentRequest.end();
+  }
+
+  setHeader(name, value) {
+    this.headers[name] = value;
+    this._currentRequest.setHeader(name, value);
+  }
+
+  removeHeader(name) {
+    delete this.headers[name];
+    this._currentRequest.removeHeader(name);
+  }
+
+  // Without this method, the test send-redirect-infinite-sync will halt the test suite
+  // TODO: investigate this further and ideally remove
+  toJSON() {
+    const { method, headers } = this._requestOptions;
+    return { uri: new URL(this.currentURL), method, headers };
+  }
+
+  _writeNext(error) {
+    if (this._currentRequest) {
+      if (error) {
+        this.emit("error", error);
+      } else if (this._bufferIndex < this._requestBodyBuffers.length) {
+        const buffer = this._requestBodyBuffers[this._bufferIndex++];
+        if (!this._currentRequest.writableEnded) {
+          this._currentRequest.write(
+            buffer.data,
+            buffer.encoding,
+            this._writeNext.bind(this)
+          );
+        }
+      } else if (this._ended) {
+        this._currentRequest.end();
+      }
+    }
+  }
+
+  _performRequest() {
+    const urlOptions = new URL(this.currentURL);
+    const scheme = urlOptions.protocol;
+    this._requestOptions.agent = this.agents[scheme.substring(0, scheme.length - 1)];
+    const { request } = scheme === "https:" ? https : http;
+    this._currentRequest = request(this.currentURL, this._requestOptions, response => {
+      this._processResponse(response);
+    });
+
+    let cookies;
+    if (this._redirectCount === 0) {
+      this.originalCookieHeader = this.getHeader("Cookie");
+    }
+    if (this.cookieJar) {
+      cookies = this.cookieJar.getCookieStringSync(this.currentURL);
+    }
+    if (cookies && cookies.length) {
+      if (this.originalCookieHeader) {
+        this.setHeader("Cookie", this.originalCookieHeader + "; " + cookies);
+      } else {
+        this.setHeader("Cookie", cookies);
+      }
+    }
+
+    for (const event of ["connect", "error", "socket", "timeout"]) {
+      this._currentRequest.on(event, (...args) => {
+        this.emit(event, ...args);
+      });
+    }
+    if (this._isRedirect) {
+      this._bufferIndex = 0;
+      this._writeNext();
+    }
+  }
+
+  _processResponse(response) {
+    const cookies = response.headers["set-cookie"];
+    if (this.cookieJar && Array.isArray(cookies)) {
+      try {
+        cookies.forEach(cookie => {
+          this.cookieJar.setCookieSync(cookie, this.currentURL, { ignoreError: true });
+        });
+      } catch (e) {
+        this.emit("error", e);
+      }
+    }
+
+    const { statusCode } = response;
+    const { location } = response.headers;
+    // In Node v15, aborting a message with remaining data causes an error to be thrown,
+    // hence the version check
+    const catchResErrors = err => {
+      if (!(majorNodeVersion >= 15 && err.message === "aborted")) {
+        this.emit("error", err);
+      }
+    };
+    response.on("error", catchResErrors);
+    let redirectAddress = null;
+    let resendWithAuth = false;
+    if (typeof location === "string" &&
+      location.length &&
+      this.followRedirects &&
+      statusCode >= 300 &&
+      statusCode < 400) {
+      redirectAddress = location;
+    } else if (statusCode === 401 &&
+      /^Basic /i.test(response.headers["www-authenticate"] || "") &&
+      (this.user && this.user.length)) {
+      this._requestOptions.auth = `${this.user}:${this.pass}`;
+      resendWithAuth = true;
+    }
+    if (redirectAddress || resendWithAuth) {
+      if (++this._redirectCount > 21) {
+        const redirectError = new Error("Maximum number of redirects exceeded");
+        redirectError.code = "ERR_TOO_MANY_REDIRECTS";
+        this.emit("error", redirectError);
+        return;
+      }
+      abortRequest(this._currentRequest);
+      response.destroy();
+      this._isRedirect = true;
+      if (((statusCode === 301 || statusCode === 302) && this._requestOptions.method === "POST") ||
+        (statusCode === 303 && !/^(?:GET|HEAD)$/.test(this._requestOptions.method))) {
+        this._requestOptions.method = "GET";
+        this._requestBodyBuffers = [];
+      }
+      let previousHostName = this._removeMatchingHeaders(/^host$/i);
+      if (!previousHostName) {
+        previousHostName = new URL(this.currentURL).hostname;
+      }
+      const previousURL = this.currentURL;
+      if (!resendWithAuth) {
+        const nextURL = redirectAddress.startsWith("https:") ?
+          new URL(redirectAddress) :
+          new URL(redirectAddress, this.currentURL);
+        if (nextURL.hostname !== previousHostName) {
+          this._removeMatchingHeaders(/^authorization$/i);
+        }
+        this.currentURL = nextURL.toString();
+      }
+      this.headers.Referer = previousURL;
+      this.emit("redirect", response, this.headers, this.currentURL);
+      try {
+        this._performRequest();
+      } catch (cause) {
+        this.emit("error", cause);
+      }
+    } else {
+      let pipeline = response;
+      const acceptEncoding = this.headers["Accept-Encoding"];
+      const requestCompressed = typeof acceptEncoding === "string" &&
+        (acceptEncoding.includes("gzip") || acceptEncoding.includes("deflate"));
+      if (
+        requestCompressed &&
+        this._requestOptions.method !== "HEAD" &&
+        statusCode >= 200 &&
+        statusCode !== 204 &&
+        statusCode !== 304
+      ) {
+        const zlibOptions = {
+          flush: zlib.constants.Z_SYNC_FLUSH,
+          finishFlush: zlib.constants.Z_SYNC_FLUSH
+        };
+        const contentEncoding = (response.headers["content-encoding"] || "identity").trim().toLowerCase();
+        if (contentEncoding === "gzip") {
+          pipeline = zlib.createGunzip(zlibOptions);
+          response.pipe(pipeline);
+        } else if (contentEncoding === "deflate") {
+          pipeline = zlib.createInflate(zlibOptions);
+          response.pipe(pipeline);
+        }
+      }
+      pipeline.removeAllListeners("error");
+      this.emit("response", response, this.currentURL);
+      pipeline.on("data", bytes => this.emit("data", bytes));
+      pipeline.once("end", bytes => this.emit("end", bytes));
+      pipeline.on("error", catchResErrors);
+      pipeline.on("close", () => this.emit("close"));
+      this._requestBodyBuffers = [];
+    }
+  }
+
+  getHeader(key, value) {
+    if (this._currentRequest) {
+      return this._currentRequest.getHeader(key, value);
+    }
+    return null;
+  }
+
+  _removeMatchingHeaders(regex) {
+    let lastValue;
+    for (const header in this.headers) {
+      if (regex.test(header)) {
+        lastValue = this.headers[header];
+        delete this.headers[header];
+      }
+    }
+    return lastValue;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/internal-constants.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/internal-constants.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/internal-constants.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+const SymbolTree = require("symbol-tree");
+
+exports.cloningSteps = Symbol("cloning steps");
+
+// TODO: the many underscore-prefixed hooks should move here
+// E.g. _attrModified (which maybe should be split into its per-spec variants)
+
+/**
+ * This SymbolTree is used to build the tree for all Node in a document
+ */
+exports.domSymbolTree = new SymbolTree("DOM SymbolTree");
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/iterable-weak-set.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/iterable-weak-set.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/iterable-weak-set.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+"use strict";
+
+// An iterable WeakSet implementation inspired by the iterable WeakMap example code in the WeakRefs specification:
+// https://github.com/tc39/proposal-weakrefs#iterable-weakmaps
+module.exports = class IterableWeakSet {
+  constructor() {
+    this._refSet = new Set();
+    this._refMap = new WeakMap();
+    this._finalizationRegistry = new FinalizationRegistry(({ ref, set }) => set.delete(ref));
+  }
+
+  add(value) {
+    if (!this._refMap.has(value)) {
+      const ref = new WeakRef(value);
+      this._refMap.set(value, ref);
+      this._refSet.add(ref);
+      this._finalizationRegistry.register(value, { ref, set: this._refSet }, ref);
+    }
+
+    return this;
+  }
+
+  delete(value) {
+    const ref = this._refMap.get(value);
+    if (!ref) {
+      return false;
+    }
+
+    this._refMap.delete(value);
+    this._refSet.delete(ref);
+    this._finalizationRegistry.unregister(ref);
+    return true;
+  }
+
+  has(value) {
+    return this._refMap.has(value);
+  }
+
+  * [Symbol.iterator]() {
+    for (const ref of this._refSet) {
+      const value = ref.deref();
+      if (value === undefined) {
+        continue;
+      }
+      yield value;
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/json.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/json.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,12 @@
+"use strict";
+
+// https://infra.spec.whatwg.org/#parse-json-from-bytes
+exports.parseJSONFromBytes = bytes => {
+  // https://encoding.spec.whatwg.org/#utf-8-decode
+  if (bytes[0] === 0xEF && bytes[1] === 0xBB && bytes[2] === 0xBF) {
+    bytes = bytes.subarray(3);
+  }
+  const jsonText = bytes.toString("utf-8");
+
+  return JSON.parse(jsonText);
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/mutation-observers.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/mutation-observers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/mutation-observers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,198 @@
+"use strict";
+
+const { domSymbolTree } = require("./internal-constants");
+const reportException = require("./runtime-script-errors");
+
+const Event = require("../generated/Event");
+const idlUtils = require("../generated/utils");
+const MutationRecord = require("../generated/MutationRecord");
+
+const MUTATION_TYPE = {
+  ATTRIBUTES: "attributes",
+  CHARACTER_DATA: "characterData",
+  CHILD_LIST: "childList"
+};
+
+// Note:
+// Since jsdom doesn't currently implement the concept of "unit of related similar-origin browsing contexts"
+// (https://html.spec.whatwg.org/multipage/browsers.html#unit-of-related-similar-origin-browsing-contexts)
+// we will approximate that the following properties are global for now.
+
+// https://dom.spec.whatwg.org/#mutation-observer-compound-microtask-queued-flag
+let mutationObserverMicrotaskQueueFlag = false;
+
+// Non-spec compliant: List of all the mutation observers with mutation records enqueued. It's a replacement for
+// mutation observer list (https://dom.spec.whatwg.org/#mutation-observer-list) but without leaking since it's empty
+// before notifying the mutation observers.
+const activeMutationObservers = new Set();
+
+// https://dom.spec.whatwg.org/#signal-slot-list
+const signalSlotList = [];
+
+// https://dom.spec.whatwg.org/#queue-a-mutation-record
+function queueMutationRecord(
+  type,
+  target,
+  name,
+  namespace,
+  oldValue,
+  addedNodes,
+  removedNodes,
+  previousSibling,
+  nextSibling
+) {
+  const interestedObservers = new Map();
+
+  const nodes = domSymbolTree.ancestorsToArray(target);
+
+  for (const node of nodes) {
+    for (const registered of node._registeredObserverList) {
+      const { options, observer: mo } = registered;
+
+      if (
+        !(node !== target && options.subtree === false) &&
+        !(type === MUTATION_TYPE.ATTRIBUTES && options.attributes !== true) &&
+        !(type === MUTATION_TYPE.ATTRIBUTES && options.attributeFilter &&
+          !options.attributeFilter.some(value => value === name || value === namespace)) &&
+        !(type === MUTATION_TYPE.CHARACTER_DATA && options.characterData !== true) &&
+        !(type === MUTATION_TYPE.CHILD_LIST && options.childList === false)
+      ) {
+        if (!interestedObservers.has(mo)) {
+          interestedObservers.set(mo, null);
+        }
+
+        if (
+          (type === MUTATION_TYPE.ATTRIBUTES && options.attributeOldValue === true) ||
+          (type === MUTATION_TYPE.CHARACTER_DATA && options.characterDataOldValue === true)
+        ) {
+          interestedObservers.set(mo, oldValue);
+        }
+      }
+    }
+  }
+
+  for (const [observer, mappedOldValue] of interestedObservers.entries()) {
+    const record = MutationRecord.createImpl(target._globalObject, [], {
+      type,
+      target,
+      attributeName: name,
+      attributeNamespace: namespace,
+      oldValue: mappedOldValue,
+      addedNodes,
+      removedNodes,
+      previousSibling,
+      nextSibling
+    });
+
+    observer._recordQueue.push(record);
+    activeMutationObservers.add(observer);
+  }
+
+  queueMutationObserverMicrotask();
+}
+
+// https://dom.spec.whatwg.org/#queue-a-tree-mutation-record
+function queueTreeMutationRecord(target, addedNodes, removedNodes, previousSibling, nextSibling) {
+  queueMutationRecord(
+    MUTATION_TYPE.CHILD_LIST,
+    target,
+    null,
+    null,
+    null,
+    addedNodes,
+    removedNodes,
+    previousSibling,
+    nextSibling
+  );
+}
+
+// https://dom.spec.whatwg.org/#queue-an-attribute-mutation-record
+function queueAttributeMutationRecord(target, name, namespace, oldValue) {
+  queueMutationRecord(
+    MUTATION_TYPE.ATTRIBUTES,
+    target,
+    name,
+    namespace,
+    oldValue,
+    [],
+    [],
+    null,
+    null
+  );
+}
+
+// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
+function queueMutationObserverMicrotask() {
+  if (mutationObserverMicrotaskQueueFlag) {
+    return;
+  }
+
+  mutationObserverMicrotaskQueueFlag = true;
+
+  Promise.resolve().then(() => {
+    notifyMutationObservers();
+  });
+}
+
+// https://dom.spec.whatwg.org/#notify-mutation-observers
+function notifyMutationObservers() {
+  mutationObserverMicrotaskQueueFlag = false;
+
+  const notifyList = [...activeMutationObservers].sort((a, b) => a._id - b._id);
+  activeMutationObservers.clear();
+
+  const signalList = [...signalSlotList];
+  signalSlotList.splice(0, signalSlotList.length);
+
+  for (const mo of notifyList) {
+    const records = [...mo._recordQueue];
+    mo._recordQueue = [];
+
+    for (const node of mo._nodeList) {
+      node._registeredObserverList = node._registeredObserverList.filter(registeredObserver => {
+        return registeredObserver.source !== mo;
+      });
+    }
+
+    if (records.length > 0) {
+      try {
+        const moWrapper = idlUtils.wrapperForImpl(mo);
+        mo._callback.call(
+          moWrapper,
+          records.map(idlUtils.wrapperForImpl),
+          moWrapper
+        );
+      } catch (e) {
+        const { target } = records[0];
+        const window = target._ownerDocument._defaultView;
+
+        reportException(window, e);
+      }
+    }
+  }
+
+  for (const slot of signalList) {
+    const slotChangeEvent = Event.createImpl(
+      slot._globalObject,
+      [
+        "slotchange",
+        { bubbles: true }
+      ],
+      { isTrusted: true }
+    );
+
+    slot._dispatch(slotChangeEvent);
+  }
+}
+
+module.exports = {
+  MUTATION_TYPE,
+
+  queueMutationRecord,
+  queueTreeMutationRecord,
+  queueAttributeMutationRecord,
+
+  queueMutationObserverMicrotask,
+
+  signalSlotList
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/namespaces.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/namespaces.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/namespaces.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,15 @@
+"use strict";
+
+// https://infra.spec.whatwg.org/#namespaces
+
+exports.HTML_NS = "http://www.w3.org/1999/xhtml";
+
+exports.MATHML_NS = "http://www.w3.org/1998/Math/MathML";
+
+exports.SVG_NS = "http://www.w3.org/2000/svg";
+
+exports.XLINK_NS = "http://www.w3.org/1999/xlink";
+
+exports.XML_NS = "http://www.w3.org/XML/1998/namespace";
+
+exports.XMLNS_NS = "http://www.w3.org/2000/xmlns/";
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/node.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/node.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/node.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,68 @@
+"use strict";
+
+const NODE_TYPE = require("../node-type");
+const { domSymbolTree } = require("./internal-constants");
+
+// https://dom.spec.whatwg.org/#concept-node-length
+function nodeLength(node) {
+  switch (node.nodeType) {
+    case NODE_TYPE.DOCUMENT_TYPE_NODE:
+      return 0;
+
+    case NODE_TYPE.TEXT_NODE:
+    case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+    case NODE_TYPE.COMMENT_NODE:
+      return node.data.length;
+
+    default:
+      return domSymbolTree.childrenCount(node);
+  }
+}
+
+// https://dom.spec.whatwg.org/#concept-tree-root
+function nodeRoot(node) {
+  while (domSymbolTree.parent(node)) {
+    node = domSymbolTree.parent(node);
+  }
+
+  return node;
+}
+
+// https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor
+function isInclusiveAncestor(ancestorNode, node) {
+  while (node) {
+    if (ancestorNode === node) {
+      return true;
+    }
+
+    node = domSymbolTree.parent(node);
+  }
+
+  return false;
+}
+
+// https://dom.spec.whatwg.org/#concept-tree-following
+function isFollowing(nodeA, nodeB) {
+  if (nodeA === nodeB) {
+    return false;
+  }
+
+  let current = nodeB;
+  while (current) {
+    if (current === nodeA) {
+      return true;
+    }
+
+    current = domSymbolTree.following(current);
+  }
+
+  return false;
+}
+
+module.exports = {
+  nodeLength,
+  nodeRoot,
+
+  isInclusiveAncestor,
+  isFollowing
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/number-and-date-inputs.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/number-and-date-inputs.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/number-and-date-inputs.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,195 @@
+"use strict";
+const { parseFloatingPointNumber } = require("./strings");
+const {
+  parseDateString,
+  parseLocalDateAndTimeString,
+  parseMonthString,
+  parseTimeString,
+  parseWeekString,
+
+  serializeDate,
+  serializeMonth,
+  serializeNormalizedDateAndTime,
+  serializeTime,
+  serializeWeek,
+  parseDateAsWeek
+} = require("./dates-and-times");
+
+// Necessary because Date.UTC() treats year within [0, 99] as [1900, 1999].
+function getUTCMs(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, millisecond = 0) {
+  if (year > 99 || year < 0) {
+    return Date.UTC(year, month - 1, day, hour, minute, second, millisecond);
+  }
+  const d = new Date(0);
+  d.setUTCFullYear(year);
+  d.setUTCMonth(month - 1);
+  d.setUTCDate(day);
+  d.setUTCHours(hour);
+  d.setUTCMinutes(minute);
+  d.setUTCSeconds(second, millisecond);
+  return d.valueOf();
+}
+
+const dayOfWeekRelMondayLUT = [-1, 0, 1, 2, 3, -3, -2];
+
+exports.convertStringToNumberByType = {
+  // https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date):concept-input-value-string-number
+  date(input) {
+    const date = parseDateString(input);
+    if (date === null) {
+      return null;
+    }
+    return getUTCMs(date.year, date.month, date.day);
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):concept-input-value-string-number
+  month(input) {
+    const date = parseMonthString(input);
+    if (date === null) {
+      return null;
+    }
+    return (date.year - 1970) * 12 + (date.month - 1);
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#week-state-(type=week):concept-input-value-string-number
+  week(input) {
+    const date = parseWeekString(input);
+    if (date === null) {
+      return null;
+    }
+    const dateObj = new Date(getUTCMs(date.year));
+    // An HTML week starts on Monday, while 0 represents Sunday. Account for such.
+    const dayOfWeekRelMonday = dayOfWeekRelMondayLUT[dateObj.getUTCDay()];
+    return dateObj.setUTCDate(1 + 7 * (date.week - 1) - dayOfWeekRelMonday);
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):concept-input-value-string-number
+  time(input) {
+    const time = parseTimeString(input);
+    if (time === null) {
+      return null;
+    }
+    return ((time.hour * 60 + time.minute) * 60 + time.second) * 1000 + time.millisecond;
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#local-date-and-time-state-(type=datetime-local):concept-input-value-string-number
+  "datetime-local"(input) {
+    const dateAndTime = parseLocalDateAndTimeString(input);
+    if (dateAndTime === null) {
+      return null;
+    }
+    const { date: { year, month, day }, time: { hour, minute, second, millisecond } } = dateAndTime;
+    // Doesn't quite matter whether or not UTC is used, since the offset from 1970-01-01 local time is returned.
+    return getUTCMs(year, month, day, hour, minute, second, millisecond);
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number):concept-input-value-string-number
+  number: parseFloatingPointNumber,
+  // https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range):concept-input-value-string-number
+  range: parseFloatingPointNumber
+};
+
+exports.convertStringToDateByType = {
+  date(input) {
+    const parsedInput = exports.convertStringToNumberByType.date(input);
+    return parsedInput === null ? null : new Date(parsedInput);
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):concept-input-value-string-number
+  month(input) {
+    const parsedMonthString = parseMonthString(input);
+    if (parsedMonthString === null) {
+      return null;
+    }
+
+    const date = new Date(0);
+    date.setUTCFullYear(parsedMonthString.year);
+    date.setUTCMonth(parsedMonthString.month - 1);
+    return date;
+  },
+  week(input) {
+    const parsedInput = exports.convertStringToNumberByType.week(input);
+    return parsedInput === null ? null : new Date(parsedInput);
+  },
+  time(input) {
+    const parsedInput = exports.convertStringToNumberByType.time(input);
+    return parsedInput === null ? null : new Date(parsedInput);
+  },
+  "datetime-local"(input) {
+    const parsedInput = exports.convertStringToNumberByType["datetime-local"](input);
+    return parsedInput === null ? null : new Date(parsedInput);
+  }
+};
+
+exports.serializeDateByType = {
+  date(input) {
+    return serializeDate({
+      year: input.getUTCFullYear(),
+      month: input.getUTCMonth() + 1,
+      day: input.getUTCDate()
+    });
+  },
+  month(input) {
+    return serializeMonth({
+      year: input.getUTCFullYear(),
+      month: input.getUTCMonth() + 1
+    });
+  },
+  week(input) {
+    return serializeWeek(parseDateAsWeek(input));
+  },
+  time(input) {
+    return serializeTime({
+      hour: input.getUTCHours(),
+      minute: input.getUTCMinutes(),
+      second: input.getUTCSeconds(),
+      millisecond: input.getUTCMilliseconds()
+    });
+  },
+  "datetime-local"(input) {
+    return serializeNormalizedDateAndTime({
+      date: {
+        year: input.getUTCFullYear(),
+        month: input.getUTCMonth() + 1,
+        day: input.getUTCDate()
+      },
+      time: {
+        hour: input.getUTCHours(),
+        minute: input.getUTCMinutes(),
+        second: input.getUTCSeconds(),
+        millisecond: input.getUTCMilliseconds()
+      }
+    });
+  }
+};
+
+exports.convertNumberToStringByType = {
+  // https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date):concept-input-value-string-number
+  date(input) {
+    return exports.serializeDateByType.date(new Date(input));
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):concept-input-value-string-date
+  month(input) {
+    const year = 1970 + Math.floor(input / 12);
+    const month = input % 12;
+    const date = new Date(0);
+    date.setUTCFullYear(year);
+    date.setUTCMonth(month);
+
+    return exports.serializeDateByType.month(date);
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#week-state-(type=week):concept-input-value-string-date
+  week(input) {
+    return exports.serializeDateByType.week(new Date(input));
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):concept-input-value-string-date
+  time(input) {
+    return exports.serializeDateByType.time(new Date(input));
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#local-date-and-time-state-(type=datetime-local):concept-input-value-number-string
+  "datetime-local"(input) {
+    return exports.serializeDateByType["datetime-local"](new Date(input));
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number):concept-input-value-number-string
+  number(input) {
+    return input.toString();
+  },
+  // https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range):concept-input-value-number-string
+  range(input) {
+    return input.toString();
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/ordered-set.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/ordered-set.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/ordered-set.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,104 @@
+"use strict";
+
+// https://infra.spec.whatwg.org/#sets
+//
+// Only use this class if a Set cannot be used, e.g. when "replace" operation is needed, since there's no way to replace
+// an element while keep the relative order using a Set, only remove and then add something at the end.
+
+module.exports = class OrderedSet {
+  constructor() {
+    this._items = [];
+  }
+
+  append(item) {
+    if (!this.contains(item)) {
+      this._items.push(item);
+    }
+  }
+
+  prepend(item) {
+    if (!this.contains(item)) {
+      this._items.unshift(item);
+    }
+  }
+
+  replace(item, replacement) {
+    let seen = false;
+    for (let i = 0; i < this._items.length;) {
+      const isInstance = this._items[i] === item || this._items[i] === replacement;
+      if (seen && isInstance) {
+        this._items.splice(i, 1);
+      } else {
+        if (isInstance) {
+          this._items[i] = replacement;
+          seen = true;
+        }
+        i++;
+      }
+    }
+  }
+
+  remove(...items) {
+    this.removePredicate(item => items.includes(item));
+  }
+
+  removePredicate(predicate) {
+    for (let i = 0; i < this._items.length;) {
+      if (predicate(this._items[i])) {
+        this._items.splice(i, 1);
+      } else {
+        i++;
+      }
+    }
+  }
+
+  empty() {
+    this._items.length = 0;
+  }
+
+  contains(item) {
+    return this._items.includes(item);
+  }
+
+  get size() {
+    return this._items.length;
+  }
+
+  isEmpty() {
+    return this._items.length === 0;
+  }
+
+  // Useful for other parts of jsdom
+
+  [Symbol.iterator]() {
+    return this._items[Symbol.iterator]();
+  }
+
+  keys() {
+    return this._items.keys();
+  }
+
+  get(index) {
+    return this._items[index];
+  }
+
+  some(func) {
+    return this._items.some(func);
+  }
+
+  // https://dom.spec.whatwg.org/#concept-ordered-set-parser
+  static parse(input) {
+    const tokens = new OrderedSet();
+    for (const token of input.split(/[\t\n\f\r ]+/)) {
+      if (token) {
+        tokens.append(token);
+      }
+    }
+    return tokens;
+  }
+
+  // https://dom.spec.whatwg.org/#concept-ordered-set-serializer
+  serialize() {
+    return this._items.join(" ");
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,76 @@
+"use strict";
+const util = require("util");
+const idlUtils = require("../generated/utils");
+const ErrorEvent = require("../generated/ErrorEvent");
+const { createAnEvent } = require("../helpers/events");
+
+const errorReportingMode = Symbol("error reporting mode");
+
+// https://html.spec.whatwg.org/multipage/webappapis.html#report-the-error
+// Omits script parameter and any check for muted errors.
+// Takes target as an EventTarget impl.
+// Takes error object, message, and location as params, unlike the spec.
+// Returns whether the event was handled or not.
+function reportAnError(line, col, target, errorObject, message, location) {
+  if (target[errorReportingMode]) {
+    return false;
+  }
+
+  target[errorReportingMode] = true;
+
+  if (typeof message !== "string") {
+    message = "uncaught exception: " + util.inspect(errorObject);
+  }
+
+  const event = createAnEvent("error", target._globalObject, ErrorEvent, {
+    cancelable: true,
+    message,
+    filename: location,
+    lineno: line,
+    colno: col,
+    error: errorObject
+  });
+
+  try {
+    target._dispatch(event);
+  } finally {
+    target[errorReportingMode] = false;
+    return event.defaultPrevented;
+  }
+}
+
+module.exports = function reportException(window, error, filenameHint) {
+  // This function will give good results on real Error objects with stacks; poor ones otherwise
+
+  const stack = error && error.stack;
+  const lines = stack && stack.split("\n");
+
+  // Find the first line that matches; important for multi-line messages
+  let pieces;
+  if (lines) {
+    for (let i = 1; i < lines.length && !pieces; ++i) {
+      pieces = lines[i].match(/at (?:(.+)\s+)?\(?(?:(.+?):(\d+):(\d+)|([^)]+))\)?/);
+    }
+  }
+
+  const fileName = (pieces && pieces[2]) || filenameHint || window._document.URL;
+  const lineNumber = (pieces && parseInt(pieces[3])) || 0;
+  const columnNumber = (pieces && parseInt(pieces[4])) || 0;
+
+  const windowImpl = idlUtils.implForWrapper(window);
+
+  const handled = reportAnError(lineNumber, columnNumber, windowImpl, error, error && error.message, fileName);
+
+  if (!handled) {
+    const errorString = shouldBeDisplayedAsError(error) ? `[${error.name}: ${error.message}]` : util.inspect(error);
+    const jsdomError = new Error(`Uncaught ${errorString}`);
+    jsdomError.detail = error;
+    jsdomError.type = "unhandled exception";
+
+    window._virtualConsole.emit("jsdomError", jsdomError);
+  }
+};
+
+function shouldBeDisplayedAsError(x) {
+  return x && x.name && x.message !== undefined && x.stack;
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/selectors.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/selectors.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/selectors.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+"use strict";
+
+const nwsapi = require("nwsapi");
+
+const idlUtils = require("../generated/utils");
+
+function initNwsapi(node) {
+  const { _globalObject, _ownerDocument } = node;
+
+  return nwsapi({
+    document: _ownerDocument,
+    DOMException: _globalObject.DOMException
+  });
+}
+
+exports.matchesDontThrow = (elImpl, selector) => {
+  const document = elImpl._ownerDocument;
+
+  if (!document._nwsapiDontThrow) {
+    document._nwsapiDontThrow = initNwsapi(elImpl);
+    document._nwsapiDontThrow.configure({
+      LOGERRORS: false,
+      VERBOSITY: false,
+      IDS_DUPES: true,
+      MIXEDCASE: true
+    });
+  }
+
+  return document._nwsapiDontThrow.match(selector, idlUtils.wrapperForImpl(elImpl));
+};
+
+// nwsapi gets `document.documentElement` at creation-time, so we have to initialize lazily, since in the initial
+// stages of Document initialization, there is no documentElement present yet.
+exports.addNwsapi = parentNode => {
+  const document = parentNode._ownerDocument;
+
+  if (!document._nwsapi) {
+    document._nwsapi = initNwsapi(parentNode);
+    document._nwsapi.configure({
+      LOGERRORS: false,
+      IDS_DUPES: true,
+      MIXEDCASE: true
+    });
+  }
+
+  return document._nwsapi;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/shadow-dom.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/shadow-dom.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/shadow-dom.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,285 @@
+"use strict";
+
+const NODE_TYPE = require("../node-type");
+
+const { nodeRoot } = require("./node");
+const { HTML_NS } = require("./namespaces");
+const { domSymbolTree } = require("./internal-constants");
+const { signalSlotList, queueMutationObserverMicrotask } = require("./mutation-observers");
+
+// Valid host element for ShadowRoot.
+// Defined in: https://dom.spec.whatwg.org/#dom-element-attachshadow
+const VALID_HOST_ELEMENT_NAME = new Set([
+  "article",
+  "aside",
+  "blockquote",
+  "body",
+  "div",
+  "footer",
+  "h1",
+  "h2",
+  "h3",
+  "h4",
+  "h5",
+  "h6",
+  "header",
+  "main",
+  "nav",
+  "p",
+  "section",
+  "span"
+]);
+
+function isValidHostElementName(name) {
+  return VALID_HOST_ELEMENT_NAME.has(name);
+}
+
+// Use an approximation by checking the presence of nodeType instead of instead of using the isImpl from
+// "../generated/Node" to avoid introduction of circular dependencies.
+function isNode(nodeImpl) {
+  return Boolean(nodeImpl && "nodeType" in nodeImpl);
+}
+
+// Use an approximation by checking the value of nodeType and presence of nodeType host instead of instead
+// of using the isImpl from "../generated/ShadowRoot" to avoid introduction of circular dependencies.
+function isShadowRoot(nodeImpl) {
+  return Boolean(nodeImpl && nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE && "host" in nodeImpl);
+}
+
+// https://dom.spec.whatwg.org/#concept-slotable
+function isSlotable(nodeImpl) {
+  return nodeImpl && (nodeImpl.nodeType === NODE_TYPE.ELEMENT_NODE || nodeImpl.nodeType === NODE_TYPE.TEXT_NODE);
+}
+
+function isSlot(nodeImpl) {
+  return nodeImpl && nodeImpl.localName === "slot" && nodeImpl._namespaceURI === HTML_NS;
+}
+
+// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
+function isShadowInclusiveAncestor(ancestor, node) {
+  while (isNode(node)) {
+    if (node === ancestor) {
+      return true;
+    }
+
+    if (isShadowRoot(node)) {
+      node = node.host;
+    } else {
+      node = domSymbolTree.parent(node);
+    }
+  }
+
+  return false;
+}
+
+// https://dom.spec.whatwg.org/#retarget
+function retarget(a, b) {
+  while (true) {
+    if (!isNode(a)) {
+      return a;
+    }
+
+    const aRoot = nodeRoot(a);
+    if (
+      !isShadowRoot(aRoot) ||
+      (isNode(b) && isShadowInclusiveAncestor(aRoot, b))
+    ) {
+      return a;
+    }
+
+    a = nodeRoot(a).host;
+  }
+}
+
+// https://dom.spec.whatwg.org/#get-the-parent
+function getEventTargetParent(eventTarget, event) {
+  // _getTheParent will be missing for Window, since it doesn't have an impl class and we don't want to pollute the
+  // user-visible global scope with a _getTheParent value. TODO: remove this entire function and use _getTheParent
+  // directly, once Window gets split into impl/wrapper.
+  return eventTarget._getTheParent ? eventTarget._getTheParent(event) : null;
+}
+
+// https://dom.spec.whatwg.org/#concept-shadow-including-root
+function shadowIncludingRoot(node) {
+  const root = nodeRoot(node);
+  return isShadowRoot(root) ? shadowIncludingRoot(root.host) : root;
+}
+
+// https://dom.spec.whatwg.org/#assign-a-slot
+function assignSlot(slotable) {
+  const slot = findSlot(slotable);
+
+  if (slot) {
+    assignSlotable(slot);
+  }
+}
+
+// https://dom.spec.whatwg.org/#assign-slotables
+function assignSlotable(slot) {
+  const slotables = findSlotable(slot);
+
+  let shouldFireSlotChange = false;
+
+  if (slotables.length !== slot._assignedNodes.length) {
+    shouldFireSlotChange = true;
+  } else {
+    for (let i = 0; i < slotables.length; i++) {
+      if (slotables[i] !== slot._assignedNodes[i]) {
+        shouldFireSlotChange = true;
+        break;
+      }
+    }
+  }
+
+  if (shouldFireSlotChange) {
+    signalSlotChange(slot);
+  }
+
+  slot._assignedNodes = slotables;
+
+  for (const slotable of slotables) {
+    slotable._assignedSlot = slot;
+  }
+}
+
+// https://dom.spec.whatwg.org/#assign-slotables-for-a-tree
+function assignSlotableForTree(root) {
+  for (const slot of domSymbolTree.treeIterator(root)) {
+    if (isSlot(slot)) {
+      assignSlotable(slot);
+    }
+  }
+}
+
+// https://dom.spec.whatwg.org/#find-slotables
+function findSlotable(slot) {
+  const result = [];
+
+  const root = nodeRoot(slot);
+  if (!isShadowRoot(root)) {
+    return result;
+  }
+
+  for (const slotable of domSymbolTree.treeIterator(root.host)) {
+    const foundSlot = findSlot(slotable);
+
+    if (foundSlot === slot) {
+      result.push(slotable);
+    }
+  }
+
+  return result;
+}
+
+// https://dom.spec.whatwg.org/#find-flattened-slotables
+function findFlattenedSlotables(slot) {
+  const result = [];
+
+  const root = nodeRoot(slot);
+  if (!isShadowRoot(root)) {
+    return result;
+  }
+
+  const slotables = findSlotable(slot);
+
+  if (slotables.length === 0) {
+    for (const child of domSymbolTree.childrenIterator(slot)) {
+      if (isSlotable(child)) {
+        slotables.push(child);
+      }
+    }
+  }
+
+  for (const node of slotables) {
+    if (isSlot(node) && isShadowRoot(nodeRoot(node))) {
+      const temporaryResult = findFlattenedSlotables(node);
+      result.push(...temporaryResult);
+    } else {
+      result.push(node);
+    }
+  }
+
+  return result;
+}
+
+// https://dom.spec.whatwg.org/#find-a-slot
+function findSlot(slotable, openFlag) {
+  const { parentNode: parent } = slotable;
+
+  if (!parent) {
+    return null;
+  }
+
+  const shadow = parent._shadowRoot;
+
+  if (!shadow || (openFlag && shadow.mode !== "open")) {
+    return null;
+  }
+
+  for (const child of domSymbolTree.treeIterator(shadow)) {
+    if (isSlot(child) && child.name === slotable._slotableName) {
+      return child;
+    }
+  }
+
+  return null;
+}
+
+// https://dom.spec.whatwg.org/#signal-a-slot-change
+function signalSlotChange(slot) {
+  if (!signalSlotList.some(entry => entry === slot)) {
+    signalSlotList.push(slot);
+  }
+
+  queueMutationObserverMicrotask();
+}
+
+// https://dom.spec.whatwg.org/#concept-shadow-including-descendant
+function* shadowIncludingInclusiveDescendantsIterator(node) {
+  yield node;
+
+  if (node._shadowRoot) {
+    yield* shadowIncludingInclusiveDescendantsIterator(node._shadowRoot);
+  }
+
+  for (const child of domSymbolTree.childrenIterator(node)) {
+    yield* shadowIncludingInclusiveDescendantsIterator(child);
+  }
+}
+
+// https://dom.spec.whatwg.org/#concept-shadow-including-descendant
+function* shadowIncludingDescendantsIterator(node) {
+  if (node._shadowRoot) {
+    yield* shadowIncludingInclusiveDescendantsIterator(node._shadowRoot);
+  }
+
+  for (const child of domSymbolTree.childrenIterator(node)) {
+    yield* shadowIncludingInclusiveDescendantsIterator(child);
+  }
+}
+
+module.exports = {
+  isValidHostElementName,
+
+  isNode,
+  isSlotable,
+  isSlot,
+  isShadowRoot,
+
+  isShadowInclusiveAncestor,
+  retarget,
+  getEventTargetParent,
+  shadowIncludingRoot,
+
+  assignSlot,
+  assignSlotable,
+  assignSlotableForTree,
+
+  findSlot,
+  findFlattenedSlotables,
+
+  signalSlotChange,
+
+  shadowIncludingInclusiveDescendantsIterator,
+  shadowIncludingDescendantsIterator
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/strings.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/strings.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/strings.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,148 @@
+"use strict";
+
+// https://infra.spec.whatwg.org/#ascii-whitespace
+const asciiWhitespaceRe = /^[\t\n\f\r ]$/;
+exports.asciiWhitespaceRe = asciiWhitespaceRe;
+
+// https://infra.spec.whatwg.org/#ascii-lowercase
+exports.asciiLowercase = s => {
+  return s.replace(/[A-Z]/g, l => l.toLowerCase());
+};
+
+// https://infra.spec.whatwg.org/#ascii-uppercase
+exports.asciiUppercase = s => {
+  return s.replace(/[a-z]/g, l => l.toUpperCase());
+};
+
+// https://infra.spec.whatwg.org/#strip-newlines
+exports.stripNewlines = s => {
+  return s.replace(/[\n\r]+/g, "");
+};
+
+// https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
+exports.stripLeadingAndTrailingASCIIWhitespace = s => {
+  return s.replace(/^[ \t\n\f\r]+/, "").replace(/[ \t\n\f\r]+$/, "");
+};
+
+// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
+exports.stripAndCollapseASCIIWhitespace = s => {
+  return s.replace(/[ \t\n\f\r]+/g, " ").replace(/^[ \t\n\f\r]+/, "").replace(/[ \t\n\f\r]+$/, "");
+};
+
+// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-simple-colour
+exports.isValidSimpleColor = s => {
+  return /^#[a-fA-F\d]{6}$/.test(s);
+};
+
+// https://infra.spec.whatwg.org/#ascii-case-insensitive
+exports.asciiCaseInsensitiveMatch = (a, b) => {
+  if (a.length !== b.length) {
+    return false;
+  }
+
+  for (let i = 0; i < a.length; ++i) {
+    if ((a.charCodeAt(i) | 32) !== (b.charCodeAt(i) | 32)) {
+      return false;
+    }
+  }
+
+  return true;
+};
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
+// Error is represented as null.
+const parseInteger = exports.parseInteger = input => {
+  // The implementation here is slightly different from the spec's. We want to use parseInt(), but parseInt() trims
+  // Unicode whitespace in addition to just ASCII ones, so we make sure that the trimmed prefix contains only ASCII
+  // whitespace ourselves.
+  const numWhitespace = input.length - input.trimStart().length;
+  if (/[^\t\n\f\r ]/.test(input.slice(0, numWhitespace))) {
+    return null;
+  }
+  // We don't allow hexadecimal numbers here.
+  // eslint-disable-next-line radix
+  const value = parseInt(input, 10);
+  if (Number.isNaN(value)) {
+    return null;
+  }
+  // parseInt() returns -0 for "-0". Normalize that here.
+  return value === 0 ? 0 : value;
+};
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
+// Error is represented as null.
+exports.parseNonNegativeInteger = input => {
+  const value = parseInteger(input);
+  if (value === null) {
+    return null;
+  }
+  if (value < 0) {
+    return null;
+  }
+  return value;
+};
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-floating-point-number
+const floatingPointNumRe = /^-?(?:\d+|\d*\.\d+)(?:[eE][-+]?\d+)?$/;
+exports.isValidFloatingPointNumber = str => floatingPointNumRe.test(str);
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values
+// Error is represented as null.
+exports.parseFloatingPointNumber = str => {
+  // The implementation here is slightly different from the spec's. We need to use parseFloat() in order to retain
+  // accuracy, but parseFloat() trims Unicode whitespace in addition to just ASCII ones, so we make sure that the
+  // trimmed prefix contains only ASCII whitespace ourselves.
+  const numWhitespace = str.length - str.trimStart().length;
+  if (/[^\t\n\f\r ]/.test(str.slice(0, numWhitespace))) {
+    return null;
+  }
+  const parsed = parseFloat(str);
+  return isFinite(parsed) ? parsed : null;
+};
+
+// https://infra.spec.whatwg.org/#split-on-ascii-whitespace
+exports.splitOnASCIIWhitespace = str => {
+  let position = 0;
+  const tokens = [];
+  while (position < str.length && asciiWhitespaceRe.test(str[position])) {
+    position++;
+  }
+  if (position === str.length) {
+    return tokens;
+  }
+  while (position < str.length) {
+    const start = position;
+    while (position < str.length && !asciiWhitespaceRe.test(str[position])) {
+      position++;
+    }
+    tokens.push(str.slice(start, position));
+    while (position < str.length && asciiWhitespaceRe.test(str[position])) {
+      position++;
+    }
+  }
+  return tokens;
+};
+
+// https://infra.spec.whatwg.org/#split-on-commas
+exports.splitOnCommas = str => {
+  let position = 0;
+  const tokens = [];
+  while (position < str.length) {
+    let start = position;
+    while (position < str.length && str[position] !== ",") {
+      position++;
+    }
+    let end = position;
+    while (start < str.length && asciiWhitespaceRe.test(str[start])) {
+      start++;
+    }
+    while (end > start && asciiWhitespaceRe.test(str[end - 1])) {
+      end--;
+    }
+    tokens.push(str.slice(start, end));
+    if (position < str.length) {
+      position++;
+    }
+  }
+  return tokens;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/style-rules.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,114 @@
+"use strict";
+const cssom = require("cssom");
+const defaultStyleSheet = require("../../browser/default-stylesheet");
+const { matchesDontThrow } = require("./selectors");
+
+const { forEach, indexOf } = Array.prototype;
+
+let parsedDefaultStyleSheet;
+
+// Properties for which getResolvedValue is implemented. This is less than
+// every supported property.
+// https://drafts.csswg.org/indexes/#properties
+exports.propertiesWithResolvedValueImplemented = {
+  __proto__: null,
+
+  // https://drafts.csswg.org/css2/visufx.html#visibility
+  visibility: {
+    inherited: true,
+    initial: "visible",
+    computedValue: "as-specified"
+  }
+};
+
+exports.forEachMatchingSheetRuleOfElement = (elementImpl, handleRule) => {
+  function handleSheet(sheet) {
+    forEach.call(sheet.cssRules, rule => {
+      if (rule.media) {
+        if (indexOf.call(rule.media, "screen") !== -1) {
+          forEach.call(rule.cssRules, innerRule => {
+            if (matches(innerRule, elementImpl)) {
+              handleRule(innerRule);
+            }
+          });
+        }
+      } else if (matches(rule, elementImpl)) {
+        handleRule(rule);
+      }
+    });
+  }
+
+  if (!parsedDefaultStyleSheet) {
+    parsedDefaultStyleSheet = cssom.parse(defaultStyleSheet);
+  }
+
+  handleSheet(parsedDefaultStyleSheet);
+  forEach.call(elementImpl._ownerDocument.styleSheets._list, handleSheet);
+};
+
+function matches(rule, element) {
+  return matchesDontThrow(element, rule.selectorText);
+}
+
+// Naive implementation of https://drafts.csswg.org/css-cascade-4/#cascading
+// based on the previous jsdom implementation of getComputedStyle.
+// Does not implement https://drafts.csswg.org/css-cascade-4/#cascade-specificity,
+// or rather specificity is only implemented by the order in which the matching
+// rules appear. The last rule is the most specific while the first rule is
+// the least specific.
+function getCascadedPropertyValue(element, property) {
+  let value = "";
+
+  exports.forEachMatchingSheetRuleOfElement(element, rule => {
+    const propertyValue = rule.style.getPropertyValue(property);
+    // getPropertyValue returns "" if the property is not found
+    if (propertyValue !== "") {
+      value = propertyValue;
+    }
+  });
+
+  const inlineValue = element.style.getPropertyValue(property);
+  if (inlineValue !== "" && inlineValue !== null) {
+    value = inlineValue;
+  }
+
+  return value;
+}
+
+// https://drafts.csswg.org/css-cascade-4/#specified-value
+function getSpecifiedValue(element, property) {
+  const cascade = getCascadedPropertyValue(element, property);
+
+  if (cascade !== "") {
+    return cascade;
+  }
+
+  // Defaulting
+  const { initial, inherited } = exports.propertiesWithResolvedValueImplemented[property];
+  if (inherited && element.parentElement !== null) {
+    return getComputedValue(element.parentElement, property);
+  }
+
+  // root element without parent element or inherited property
+  return initial;
+}
+
+// https://drafts.csswg.org/css-cascade-4/#computed-value
+function getComputedValue(element, property) {
+  const { computedValue } = exports.propertiesWithResolvedValueImplemented[property];
+  if (computedValue === "as-specified") {
+    return getSpecifiedValue(element, property);
+  }
+
+  throw new TypeError(`Internal error: unrecognized computed value instruction '${computedValue}'`);
+}
+
+// https://drafts.csswg.org/cssom/#resolved-value
+// Only implements `visibility`
+exports.getResolvedValue = (element, property) => {
+  // Determined for special case properties, none of which are implemented here.
+  // So we skip to "any other property: The resolved value is the computed value."
+  return getComputedValue(element, property);
+};
+
+exports.SHADOW_DOM_PSEUDO_REGEXP = /^::(?:part|slotted)\(/i;
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/stylesheets.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,113 @@
+"use strict";
+const cssom = require("cssom");
+const whatwgEncoding = require("whatwg-encoding");
+const whatwgURL = require("whatwg-url");
+
+// TODO: this should really implement https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet
+// It (and the things it calls) is nowhere close right now.
+exports.fetchStylesheet = (elementImpl, urlString) => {
+  const parsedURL = whatwgURL.parseURL(urlString);
+  return fetchStylesheetInternal(elementImpl, urlString, parsedURL);
+};
+
+// https://drafts.csswg.org/cssom/#remove-a-css-style-sheet
+exports.removeStylesheet = (sheet, elementImpl) => {
+  const { styleSheets } = elementImpl._ownerDocument;
+  styleSheets._remove(sheet);
+
+  // Remove the association explicitly; in the spec it's implicit so this step doesn't exist.
+  elementImpl.sheet = null;
+
+  // TODO: "Set the CSS style sheet’s parent CSS style sheet, owner node and owner CSS rule to null."
+  // Probably when we have a real CSSOM implementation.
+};
+
+// https://drafts.csswg.org/cssom/#create-a-css-style-sheet kinda:
+// - Parsing failures are not handled gracefully like they should be
+// - The import rules stuff seems out of place, and probably should affect the load event...
+exports.createStylesheet = (sheetText, elementImpl, baseURL) => {
+  let sheet;
+  try {
+    sheet = cssom.parse(sheetText);
+  } catch (e) {
+    if (elementImpl._ownerDocument._defaultView) {
+      const error = new Error("Could not parse CSS stylesheet");
+      error.detail = sheetText;
+      error.type = "css parsing";
+
+      elementImpl._ownerDocument._defaultView._virtualConsole.emit("jsdomError", error);
+    }
+    return;
+  }
+
+  scanForImportRules(elementImpl, sheet.cssRules, baseURL);
+
+  addStylesheet(sheet, elementImpl);
+};
+
+// https://drafts.csswg.org/cssom/#add-a-css-style-sheet
+function addStylesheet(sheet, elementImpl) {
+  elementImpl._ownerDocument.styleSheets._add(sheet);
+
+  // Set the association explicitly; in the spec it's implicit.
+  elementImpl.sheet = sheet;
+
+  // TODO: title and disabled stuff
+}
+
+function fetchStylesheetInternal(elementImpl, urlString, parsedURL) {
+  const document = elementImpl._ownerDocument;
+  let defaultEncoding = document._encoding;
+  const resourceLoader = document._resourceLoader;
+
+  if (elementImpl.localName === "link" && elementImpl.hasAttributeNS(null, "charset")) {
+    defaultEncoding = whatwgEncoding.labelToName(elementImpl.getAttributeNS(null, "charset"));
+  }
+
+  function onStylesheetLoad(data) {
+    const css = whatwgEncoding.decode(data, defaultEncoding);
+
+    // TODO: MIME type checking?
+    if (elementImpl.sheet) {
+      exports.removeStylesheet(elementImpl.sheet, elementImpl);
+    }
+    exports.createStylesheet(css, elementImpl, parsedURL);
+  }
+
+  resourceLoader.fetch(urlString, {
+    element: elementImpl,
+    onLoad: onStylesheetLoad
+  });
+}
+
+// TODO this is actually really messed up and overwrites the sheet on elementImpl
+// Tracking in https://github.com/jsdom/jsdom/issues/2124
+function scanForImportRules(elementImpl, cssRules, baseURL) {
+  if (!cssRules) {
+    return;
+  }
+
+  for (let i = 0; i < cssRules.length; ++i) {
+    if (cssRules[i].cssRules) {
+      // @media rule: keep searching inside it.
+      scanForImportRules(elementImpl, cssRules[i].cssRules, baseURL);
+    } else if (cssRules[i].href) {
+      // @import rule: fetch the resource and evaluate it.
+      // See http://dev.w3.org/csswg/cssom/#css-import-rule
+      //     If loading of the style sheet fails its cssRules list is simply
+      //     empty. I.e. an @import rule always has an associated style sheet.
+      const parsed = whatwgURL.parseURL(cssRules[i].href, { baseURL });
+      if (parsed === null) {
+        const window = elementImpl._ownerDocument._defaultView;
+        if (window) {
+          const error = new Error(`Could not parse CSS @import URL ${cssRules[i].href} relative to base URL ` +
+                                  `"${whatwgURL.serializeURL(baseURL)}"`);
+          error.type = "css @import URL parsing";
+          window._virtualConsole.emit("jsdomError", error);
+        }
+      } else {
+        fetchStylesheetInternal(elementImpl, whatwgURL.serializeURL(parsed), parsed);
+      }
+    }
+  }
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/svg/basic-types.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/svg/basic-types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/svg/basic-types.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,41 @@
+"use strict";
+
+// https://svgwg.org/svg2-draft/types.html#TermDetach
+function detach(value) {
+  if (typeof value === "string") {
+    return;
+  }
+
+  throw new TypeError(`jsdom internal error: detaching object of wrong type ${value}`);
+}
+exports.detach = detach;
+
+// https://svgwg.org/svg2-draft/types.html#TermAttach
+// listObject corresponds to the parameter taken by the algorithm in the spec, but is currently unused because only
+// DOMString type is supported by jsdom (and this function) right now.
+// eslint-disable-next-line no-unused-vars
+function attach(value, listObject) {
+  if (typeof value === "string") {
+    return;
+  }
+
+  throw new TypeError(`jsdom internal error: attaching object of wrong type ${value}`);
+}
+exports.attach = attach;
+
+// https://svgwg.org/svg2-draft/types.html#TermReserialize for DOMString.
+function reserializeSpaceSeparatedTokens(elements) {
+  return elements.join(" ");
+}
+exports.reserializeSpaceSeparatedTokens = reserializeSpaceSeparatedTokens;
+
+// Used for systemLanguage attribute, whose value is a set of comma-separated tokens:
+// https://svgwg.org/svg2-draft/struct.html#SystemLanguageAttribute
+// SVG 2 spec (https://svgwg.org/svg2-draft/types.html#TermReserialize) says any SVGStringList should reserialize the
+// same way, as space-separated tokens, but doing so for systemLanguage is illogical and contradicts the Firefox
+// behavior.
+// I cannot find a description of reserialization of SVGStringList in the SVG 1.1 spec.
+function reserializeCommaSeparatedTokens(elements) {
+  return elements.join(", ");
+}
+exports.reserializeCommaSeparatedTokens = reserializeCommaSeparatedTokens;
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/svg/render.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/svg/render.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/svg/render.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,46 @@
+"use strict";
+const { SVG_NS } = require("../namespaces");
+
+// https://svgwg.org/svg2-draft/render.html#TermNeverRenderedElement
+const neverRenderedElements = new Set([
+  "clipPath",
+  "defs",
+  "desc",
+  "linearGradient",
+  "marker",
+  "mask",
+  "metadata",
+  "pattern",
+  "radialGradient",
+  "script",
+  "style",
+  "title",
+  "symbol"
+]);
+
+// https://svgwg.org/svg2-draft/render.html#Rendered-vs-NonRendered
+exports.isRenderedElement = elImpl => {
+  if (neverRenderedElements.has(elImpl._localName)) {
+    return false;
+  }
+
+  // This does not check for elements excluded because of conditional processing attributes or ‘switch’ structures,
+  // because conditional processing is not implemented.
+  // https://svgwg.org/svg2-draft/struct.html#ConditionalProcessing
+
+  // This does not check for computed style of display being none, since that is not yet implemented for HTML
+  // focusability either (and there are no tests yet).
+
+  if (!elImpl.isConnected) {
+    return false;
+  }
+
+  // The spec is unclear about how to deal with non-SVG parents, so we only perform this check for SVG-namespace
+  // parents.
+  if (elImpl.parentElement && elImpl.parentElement._namespaceURI === SVG_NS &&
+                              !exports.isRenderedElement(elImpl.parentNode)) {
+    return false;
+  }
+
+  return true;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/text.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/text.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,19 @@
+"use strict";
+const { domSymbolTree } = require("./internal-constants");
+const { CDATA_SECTION_NODE, TEXT_NODE } = require("../node-type");
+
+//
+// https://dom.spec.whatwg.org/#concept-child-text-content
+//
+exports.childTextContent = node => {
+  let result = "";
+  const iterator = domSymbolTree.childrenIterator(node);
+  for (const child of iterator) {
+    if (child.nodeType === TEXT_NODE ||
+        // The CDataSection extends Text.
+        child.nodeType === CDATA_SECTION_NODE) {
+      result += child.data;
+    }
+  }
+  return result;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/traversal.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/traversal.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/traversal.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,72 @@
+"use strict";
+const { domSymbolTree } = require("./internal-constants");
+const { HTML_NS } = require("./namespaces");
+
+// All these operate on and return impls, not wrappers!
+
+exports.closest = (e, localName, namespace = HTML_NS) => {
+  while (e) {
+    if (e.localName === localName && e.namespaceURI === namespace) {
+      return e;
+    }
+    e = domSymbolTree.parent(e);
+  }
+
+  return null;
+};
+
+exports.childrenByLocalName = (parent, localName, namespace = HTML_NS) => {
+  return domSymbolTree.childrenToArray(parent, { filter(node) {
+    return node._localName === localName && node._namespaceURI === namespace;
+  } });
+};
+
+exports.descendantsByLocalName = (parent, localName, namespace = HTML_NS) => {
+  return domSymbolTree.treeToArray(parent, { filter(node) {
+    return node._localName === localName && node._namespaceURI === namespace && node !== parent;
+  } });
+};
+
+exports.childrenByLocalNames = (parent, localNamesSet, namespace = HTML_NS) => {
+  return domSymbolTree.childrenToArray(parent, { filter(node) {
+    return localNamesSet.has(node._localName) && node._namespaceURI === namespace;
+  } });
+};
+
+exports.descendantsByLocalNames = (parent, localNamesSet, namespace = HTML_NS) => {
+  return domSymbolTree.treeToArray(parent, { filter(node) {
+    return localNamesSet.has(node._localName) &&
+           node._namespaceURI === namespace &&
+           node !== parent;
+  } });
+};
+
+exports.firstChildWithLocalName = (parent, localName, namespace = HTML_NS) => {
+  const iterator = domSymbolTree.childrenIterator(parent);
+  for (const child of iterator) {
+    if (child._localName === localName && child._namespaceURI === namespace) {
+      return child;
+    }
+  }
+  return null;
+};
+
+exports.firstChildWithLocalNames = (parent, localNamesSet, namespace = HTML_NS) => {
+  const iterator = domSymbolTree.childrenIterator(parent);
+  for (const child of iterator) {
+    if (localNamesSet.has(child._localName) && child._namespaceURI === namespace) {
+      return child;
+    }
+  }
+  return null;
+};
+
+exports.firstDescendantWithLocalName = (parent, localName, namespace = HTML_NS) => {
+  const iterator = domSymbolTree.treeIterator(parent);
+  for (const descendant of iterator) {
+    if (descendant._localName === localName && descendant._namespaceURI === namespace) {
+      return descendant;
+    }
+  }
+  return null;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/helpers/validate-names.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/helpers/validate-names.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/helpers/validate-names.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,75 @@
+"use strict";
+const xnv = require("xml-name-validator");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { XML_NS, XMLNS_NS } = require("../helpers/namespaces");
+
+// https://dom.spec.whatwg.org/#validate
+
+exports.name = function (globalObject, name) {
+  const result = xnv.name(name);
+  if (!result.success) {
+    throw DOMException.create(globalObject, [
+      `"${name}" did not match the Name production: ${result.error}`,
+      "InvalidCharacterError"
+    ]);
+  }
+};
+
+exports.qname = function (globalObject, qname) {
+  exports.name(globalObject, qname);
+
+  const result = xnv.qname(qname);
+  if (!result.success) {
+    throw DOMException.create(globalObject, [
+      `"${qname}" did not match the QName production: ${result.error}`,
+      "InvalidCharacterError"
+    ]);
+  }
+};
+
+exports.validateAndExtract = function (globalObject, namespace, qualifiedName) {
+  if (namespace === "") {
+    namespace = null;
+  }
+
+  exports.qname(globalObject, qualifiedName);
+
+  let prefix = null;
+  let localName = qualifiedName;
+
+  const colonIndex = qualifiedName.indexOf(":");
+  if (colonIndex !== -1) {
+    prefix = qualifiedName.substring(0, colonIndex);
+    localName = qualifiedName.substring(colonIndex + 1);
+  }
+
+  if (prefix !== null && namespace === null) {
+    throw DOMException.create(globalObject, [
+      "A namespace was given but a prefix was also extracted from the qualifiedName",
+      "NamespaceError"
+    ]);
+  }
+
+  if (prefix === "xml" && namespace !== XML_NS) {
+    throw DOMException.create(globalObject, [
+      "A prefix of \"xml\" was given but the namespace was not the XML namespace",
+      "NamespaceError"
+    ]);
+  }
+
+  if ((qualifiedName === "xmlns" || prefix === "xmlns") && namespace !== XMLNS_NS) {
+    throw DOMException.create(globalObject, [
+      "A prefix or qualifiedName of \"xmlns\" was given but the namespace was not the XMLNS namespace",
+      "NamespaceError"
+    ]);
+  }
+
+  if (namespace === XMLNS_NS && qualifiedName !== "xmlns" && prefix !== "xmlns") {
+    throw DOMException.create(globalObject, [
+      "The XMLNS namespace was given but neither the prefix nor qualifiedName was \"xmlns\"",
+      "NamespaceError"
+    ]);
+  }
+
+  return { namespace, prefix, localName };
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/hr-time/Performance-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/hr-time/Performance-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/hr-time/Performance-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+"use strict";
+
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+
+class PerformanceImpl extends EventTargetImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._rawPerformance = privateData.rawPerformance;
+  }
+
+  now() {
+    return this._rawPerformance.now();
+  }
+
+  get timeOrigin() {
+    return this._rawPerformance.timeOrigin;
+  }
+
+  toJSON() {
+    return this._rawPerformance.toJSON();
+  }
+}
+
+exports.implementation = PerformanceImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/interfaces.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/interfaces.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/interfaces.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,217 @@
+/* eslint-disable global-require */
+"use strict";
+
+const style = require("../level2/style");
+const xpath = require("../level3/xpath");
+
+// This object defines the mapping between the interface name and the generated interface wrapper code.
+// Note: The mapping needs to stay as-is in order due to interface evaluation.
+// We cannot "refactor" this to something less duplicative because that would break bundlers which depend on static
+// analysis of require()s.
+const generatedInterfaces = {
+  DOMException: require("domexception/webidl2js-wrapper"),
+
+  URL: require("whatwg-url/webidl2js-wrapper").URL,
+  URLSearchParams: require("whatwg-url/webidl2js-wrapper").URLSearchParams,
+
+  EventTarget: require("./generated/EventTarget"),
+
+  NamedNodeMap: require("./generated/NamedNodeMap"),
+  Node: require("./generated/Node"),
+  Attr: require("./generated/Attr"),
+  Element: require("./generated/Element"),
+  DocumentFragment: require("./generated/DocumentFragment"),
+  DOMImplementation: require("./generated/DOMImplementation"),
+  Document: require("./generated/Document"),
+  XMLDocument: require("./generated/XMLDocument"),
+  CharacterData: require("./generated/CharacterData"),
+  Text: require("./generated/Text"),
+  CDATASection: require("./generated/CDATASection"),
+  ProcessingInstruction: require("./generated/ProcessingInstruction"),
+  Comment: require("./generated/Comment"),
+  DocumentType: require("./generated/DocumentType"),
+  NodeList: require("./generated/NodeList"),
+  HTMLCollection: require("./generated/HTMLCollection"),
+  HTMLOptionsCollection: require("./generated/HTMLOptionsCollection"),
+  DOMStringMap: require("./generated/DOMStringMap"),
+  DOMTokenList: require("./generated/DOMTokenList"),
+
+  StyleSheetList: require("./generated/StyleSheetList.js"),
+
+  HTMLElement: require("./generated/HTMLElement.js"),
+  HTMLHeadElement: require("./generated/HTMLHeadElement.js"),
+  HTMLTitleElement: require("./generated/HTMLTitleElement.js"),
+  HTMLBaseElement: require("./generated/HTMLBaseElement.js"),
+  HTMLLinkElement: require("./generated/HTMLLinkElement.js"),
+  HTMLMetaElement: require("./generated/HTMLMetaElement.js"),
+  HTMLStyleElement: require("./generated/HTMLStyleElement.js"),
+  HTMLBodyElement: require("./generated/HTMLBodyElement.js"),
+  HTMLHeadingElement: require("./generated/HTMLHeadingElement.js"),
+  HTMLParagraphElement: require("./generated/HTMLParagraphElement.js"),
+  HTMLHRElement: require("./generated/HTMLHRElement.js"),
+  HTMLPreElement: require("./generated/HTMLPreElement.js"),
+  HTMLUListElement: require("./generated/HTMLUListElement.js"),
+  HTMLOListElement: require("./generated/HTMLOListElement.js"),
+  HTMLLIElement: require("./generated/HTMLLIElement.js"),
+  HTMLMenuElement: require("./generated/HTMLMenuElement.js"),
+  HTMLDListElement: require("./generated/HTMLDListElement.js"),
+  HTMLDivElement: require("./generated/HTMLDivElement.js"),
+  HTMLAnchorElement: require("./generated/HTMLAnchorElement.js"),
+  HTMLAreaElement: require("./generated/HTMLAreaElement.js"),
+  HTMLBRElement: require("./generated/HTMLBRElement.js"),
+  HTMLButtonElement: require("./generated/HTMLButtonElement.js"),
+  HTMLCanvasElement: require("./generated/HTMLCanvasElement.js"),
+  HTMLDataElement: require("./generated/HTMLDataElement.js"),
+  HTMLDataListElement: require("./generated/HTMLDataListElement.js"),
+  HTMLDetailsElement: require("./generated/HTMLDetailsElement.js"),
+  HTMLDialogElement: require("./generated/HTMLDialogElement.js"),
+  HTMLDirectoryElement: require("./generated/HTMLDirectoryElement.js"),
+  HTMLFieldSetElement: require("./generated/HTMLFieldSetElement.js"),
+  HTMLFontElement: require("./generated/HTMLFontElement.js"),
+  HTMLFormElement: require("./generated/HTMLFormElement.js"),
+  HTMLHtmlElement: require("./generated/HTMLHtmlElement.js"),
+  HTMLImageElement: require("./generated/HTMLImageElement.js"),
+  HTMLInputElement: require("./generated/HTMLInputElement.js"),
+  HTMLLabelElement: require("./generated/HTMLLabelElement.js"),
+  HTMLLegendElement: require("./generated/HTMLLegendElement.js"),
+  HTMLMapElement: require("./generated/HTMLMapElement.js"),
+  HTMLMarqueeElement: require("./generated/HTMLMarqueeElement.js"),
+  HTMLMediaElement: require("./generated/HTMLMediaElement.js"),
+  HTMLMeterElement: require("./generated/HTMLMeterElement.js"),
+  HTMLModElement: require("./generated/HTMLModElement.js"),
+  HTMLOptGroupElement: require("./generated/HTMLOptGroupElement.js"),
+  HTMLOptionElement: require("./generated/HTMLOptionElement.js"),
+  HTMLOutputElement: require("./generated/HTMLOutputElement.js"),
+  HTMLPictureElement: require("./generated/HTMLPictureElement.js"),
+  HTMLProgressElement: require("./generated/HTMLProgressElement.js"),
+  HTMLQuoteElement: require("./generated/HTMLQuoteElement.js"),
+  HTMLScriptElement: require("./generated/HTMLScriptElement.js"),
+  HTMLSelectElement: require("./generated/HTMLSelectElement.js"),
+  HTMLSlotElement: require("./generated/HTMLSlotElement.js"),
+  HTMLSourceElement: require("./generated/HTMLSourceElement.js"),
+  HTMLSpanElement: require("./generated/HTMLSpanElement.js"),
+  HTMLTableCaptionElement: require("./generated/HTMLTableCaptionElement.js"),
+  HTMLTableCellElement: require("./generated/HTMLTableCellElement.js"),
+  HTMLTableColElement: require("./generated/HTMLTableColElement.js"),
+  HTMLTableElement: require("./generated/HTMLTableElement.js"),
+  HTMLTimeElement: require("./generated/HTMLTimeElement.js"),
+  HTMLTableRowElement: require("./generated/HTMLTableRowElement.js"),
+  HTMLTableSectionElement: require("./generated/HTMLTableSectionElement.js"),
+  HTMLTemplateElement: require("./generated/HTMLTemplateElement.js"),
+  HTMLTextAreaElement: require("./generated/HTMLTextAreaElement.js"),
+  HTMLUnknownElement: require("./generated/HTMLUnknownElement.js"),
+  HTMLFrameElement: require("./generated/HTMLFrameElement.js"),
+  HTMLFrameSetElement: require("./generated/HTMLFrameSetElement.js"),
+  HTMLIFrameElement: require("./generated/HTMLIFrameElement.js"),
+  HTMLEmbedElement: require("./generated/HTMLEmbedElement.js"),
+  HTMLObjectElement: require("./generated/HTMLObjectElement.js"),
+  HTMLParamElement: require("./generated/HTMLParamElement.js"),
+  HTMLVideoElement: require("./generated/HTMLVideoElement.js"),
+  HTMLAudioElement: require("./generated/HTMLAudioElement.js"),
+  HTMLTrackElement: require("./generated/HTMLTrackElement.js"),
+
+  SVGElement: require("./generated/SVGElement.js"),
+  SVGGraphicsElement: require("./generated/SVGGraphicsElement.js"),
+  SVGSVGElement: require("./generated/SVGSVGElement.js"),
+  SVGTitleElement: require("./generated/SVGTitleElement.js"),
+  SVGAnimatedString: require("./generated/SVGAnimatedString"),
+  SVGNumber: require("./generated/SVGNumber"),
+  SVGStringList: require("./generated/SVGStringList"),
+
+  Event: require("./generated/Event"),
+  CloseEvent: require("./generated/CloseEvent"),
+  CustomEvent: require("./generated/CustomEvent"),
+  MessageEvent: require("./generated/MessageEvent"),
+  ErrorEvent: require("./generated/ErrorEvent"),
+  HashChangeEvent: require("./generated/HashChangeEvent"),
+  PopStateEvent: require("./generated/PopStateEvent"),
+  StorageEvent: require("./generated/StorageEvent"),
+  ProgressEvent: require("./generated/ProgressEvent"),
+  PageTransitionEvent: require("./generated/PageTransitionEvent"),
+
+  UIEvent: require("./generated/UIEvent"),
+  FocusEvent: require("./generated/FocusEvent"),
+  InputEvent: require("./generated/InputEvent"),
+  MouseEvent: require("./generated/MouseEvent"),
+  KeyboardEvent: require("./generated/KeyboardEvent"),
+  TouchEvent: require("./generated/TouchEvent"),
+  CompositionEvent: require("./generated/CompositionEvent"),
+  WheelEvent: require("./generated/WheelEvent"),
+
+  BarProp: require("./generated/BarProp"),
+  External: require("./generated/External"),
+  Location: require("./generated/Location"),
+  History: require("./generated/History"),
+  Screen: require("./generated/Screen"),
+  Performance: require("./generated/Performance"),
+  Navigator: require("./generated/Navigator"),
+
+  PluginArray: require("./generated/PluginArray"),
+  MimeTypeArray: require("./generated/MimeTypeArray"),
+  Plugin: require("./generated/Plugin"),
+  MimeType: require("./generated/MimeType"),
+
+  FileReader: require("./generated/FileReader"),
+  Blob: require("./generated/Blob"),
+  File: require("./generated/File"),
+  FileList: require("./generated/FileList"),
+  ValidityState: require("./generated/ValidityState"),
+
+  DOMParser: require("./generated/DOMParser"),
+  XMLSerializer: require("./generated/XMLSerializer"),
+
+  FormData: require("./generated/FormData"),
+  XMLHttpRequestEventTarget: require("./generated/XMLHttpRequestEventTarget"),
+  XMLHttpRequestUpload: require("./generated/XMLHttpRequestUpload"),
+  XMLHttpRequest: require("./generated/XMLHttpRequest"),
+  WebSocket: require("./generated/WebSocket"),
+
+  NodeFilter: require("./generated/NodeFilter"),
+  NodeIterator: require("./generated/NodeIterator"),
+  TreeWalker: require("./generated/TreeWalker"),
+
+  AbstractRange: require("./generated/AbstractRange"),
+  Range: require("./generated/Range"),
+  StaticRange: require("./generated/StaticRange"),
+  Selection: require("./generated/Selection"),
+
+  Storage: require("./generated/Storage"),
+
+  CustomElementRegistry: require("./generated/CustomElementRegistry"),
+  ShadowRoot: require("./generated/ShadowRoot"),
+
+  MutationObserver: require("./generated/MutationObserver"),
+  MutationRecord: require("./generated/MutationRecord"),
+
+  Headers: require("./generated/Headers"),
+  AbortController: require("./generated/AbortController"),
+  AbortSignal: require("./generated/AbortSignal")
+};
+
+function install(window, name, interfaceConstructor) {
+  Object.defineProperty(window, name, {
+    configurable: true,
+    writable: true,
+    value: interfaceConstructor
+  });
+}
+
+exports.installInterfaces = (window, globalNames) => {
+  // Install generated interface.
+  for (const generatedInterface of Object.values(generatedInterfaces)) {
+    generatedInterface.install(window, globalNames);
+  }
+
+  // Install legacy HTMLDocument interface
+  // https://html.spec.whatwg.org/#htmldocument
+  install(window, "HTMLDocument", window.Document);
+
+  // These need to be cleaned up...
+  style.addToCore(window);
+  xpath(window);
+};
+
+// Returns an interface webidl2js wrapper given its an interface name.
+exports.getInterfaceWrapper = name => {
+  return generatedInterfaces[name];
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/mutation-observer/MutationObserver-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/mutation-observer/MutationObserver-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/mutation-observer/MutationObserver-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+"use strict";
+
+const { wrapperForImpl } = require("../generated/utils");
+
+// If we were to implement the MutationObserver by spec, the MutationObservers will not be collected by the GC because
+// all the MO are kept in a mutation observer list (https://github.com/jsdom/jsdom/pull/2398/files#r238123889). The
+// mutation observer list is primarily used to invoke the mutation observer callback in the same order than the
+// mutation observer creation.
+// In order to get around this issue, we will assign an increasing id for each mutation observer, this way we would be
+// able to invoke the callback in the creation order without having to keep a list of all the mutation observers.
+let mutationObserverId = 0;
+
+// https://dom.spec.whatwg.org/#mutationobserver
+class MutationObserverImpl {
+  // https://dom.spec.whatwg.org/#dom-mutationobserver-mutationobserver
+  constructor(globalObject, args) {
+    const [callback] = args;
+
+    this._callback = callback;
+    this._nodeList = [];
+    this._recordQueue = [];
+
+    this._id = ++mutationObserverId;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-mutationobserver-observe
+  observe(target, options) {
+    if (("attributeOldValue" in options || "attributeFilter" in options) && !("attributes" in options)) {
+      options.attributes = true;
+    }
+
+    if ("characterDataOldValue" in options & !("characterData" in options)) {
+      options.characterData = true;
+    }
+
+    if (!options.childList && !options.attributes && !options.characterData) {
+      throw new TypeError("The options object must set at least one of 'attributes', 'characterData', or 'childList' " +
+        "to true.");
+    } else if (options.attributeOldValue && !options.attributes) {
+      throw new TypeError("The options object may only set 'attributeOldValue' to true when 'attributes' is true or " +
+        "not present.");
+    } else if (("attributeFilter" in options) && !options.attributes) {
+      throw new TypeError("The options object may only set 'attributeFilter' when 'attributes' is true or not " +
+        "present.");
+    } else if (options.characterDataOldValue && !options.characterData) {
+      throw new TypeError("The options object may only set 'characterDataOldValue' to true when 'characterData' is " +
+        "true or not present.");
+    }
+
+    const existingRegisteredObserver = target._registeredObserverList.find(registeredObserver => {
+      return registeredObserver.observer === this;
+    });
+
+    if (existingRegisteredObserver) {
+      for (const node of this._nodeList) {
+        node._registeredObserverList = node._registeredObserverList.filter(registeredObserver => {
+          return registeredObserver.source !== existingRegisteredObserver;
+        });
+      }
+
+      existingRegisteredObserver.options = options;
+    } else {
+      target._registeredObserverList.push({
+        observer: this,
+        options
+      });
+
+      this._nodeList.push(target);
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#dom-mutationobserver-disconnect
+  disconnect() {
+    for (const node of this._nodeList) {
+      node._registeredObserverList = node._registeredObserverList.filter(registeredObserver => {
+        return registeredObserver.observer !== this;
+      });
+    }
+
+    this._recordQueue = [];
+  }
+
+  // https://dom.spec.whatwg.org/#dom-mutationobserver-takerecords
+  takeRecords() {
+    // TODO: revisit if https://github.com/jsdom/webidl2js/pull/108 gets fixed.
+    const records = this._recordQueue.map(wrapperForImpl);
+    this._recordQueue = [];
+
+    return records;
+  }
+}
+
+module.exports = {
+  implementation: MutationObserverImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/mutation-observer/MutationRecord-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/mutation-observer/MutationRecord-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/mutation-observer/MutationRecord-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+"use strict";
+
+const NodeList = require("../generated/NodeList");
+
+// https://dom.spec.whatwg.org/#mutationrecord
+class MutationRecordImpl {
+  constructor(globalObject, args, privateData) {
+    this._globalObject = globalObject;
+
+    this.type = privateData.type;
+    this.target = privateData.target;
+    this.previousSibling = privateData.previousSibling;
+    this.nextSibling = privateData.nextSibling;
+    this.attributeName = privateData.attributeName;
+    this.attributeNamespace = privateData.attributeNamespace;
+    this.oldValue = privateData.oldValue;
+
+    this._addedNodes = privateData.addedNodes;
+    this._removedNodes = privateData.removedNodes;
+  }
+
+  get addedNodes() {
+    return NodeList.createImpl(this._globalObject, [], {
+      nodes: this._addedNodes
+    });
+  }
+
+  get removedNodes() {
+    return NodeList.createImpl(this._globalObject, [], {
+      nodes: this._removedNodes
+    });
+  }
+}
+
+module.exports = {
+  implementation: MutationRecordImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/named-properties-window.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/named-properties-window.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/named-properties-window.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,141 @@
+"use strict";
+const hasOwnProp = Object.prototype.hasOwnProperty;
+const namedPropertiesTracker = require("../named-properties-tracker");
+const NODE_TYPE = require("./node-type");
+const HTMLCollection = require("./generated/HTMLCollection");
+const { treeOrderSorter } = require("../utils");
+const idlUtils = require("./generated/utils");
+
+function isNamedPropertyElement(element) {
+  // (for the name attribute)
+
+  // use hasOwnProperty to make sure contentWindow comes from the prototype,
+  // and is not set directly on the node by a script.
+  if ("contentWindow" in element && !hasOwnProp.call(element, "contentWindow")) {
+    return true;
+  }
+
+  switch (element.nodeName) {
+    case "A":
+    case "AREA":
+    case "EMBED":
+    case "FORM":
+    case "FRAMESET":
+    case "IMG":
+    case "OBJECT":
+      return true;
+    default:
+      return false;
+  }
+}
+
+function namedPropertyResolver(window, name, values) {
+  function getResult() {
+    const results = [];
+
+    for (const node of values().keys()) {
+      if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+        continue;
+      }
+
+      if (node.getAttributeNS(null, "id") === name) {
+        results.push(node);
+      } else if (node.getAttributeNS(null, "name") === name && isNamedPropertyElement(node)) {
+        results.push(node);
+      }
+    }
+
+    results.sort(treeOrderSorter);
+
+    return results;
+  }
+
+  const document = window._document;
+  const objects = HTMLCollection.create(window, [], {
+    element: idlUtils.implForWrapper(document.documentElement),
+    query: getResult
+  });
+
+  const { length } = objects;
+  for (let i = 0; i < length; ++i) {
+    const node = objects[i];
+
+    if ("contentWindow" in node && !hasOwnProp.call(node, "contentWindow") &&
+       node.getAttributeNS(null, "name") === name) {
+      return node.contentWindow;
+    }
+  }
+
+  if (length === 0) {
+    return undefined;
+  }
+
+  if (length === 1) {
+    return objects[0];
+  }
+
+  return objects;
+}
+
+exports.initializeWindow = function (window, windowProxy) {
+  namedPropertiesTracker.create(window, windowProxy, namedPropertyResolver.bind(null));
+};
+
+exports.elementAttributeModified = function (element, name, value, oldValue) {
+  if (!element._attached) {
+    return;
+  }
+
+  const useName = isNamedPropertyElement(element);
+
+  if (name === "id" || (name === "name" && useName)) {
+    const tracker = namedPropertiesTracker.get(element._ownerDocument._global);
+
+    // (tracker will be null if the document has no Window)
+    if (tracker) {
+      if (name === "id" && (!useName || element.getAttributeNS(null, "name") !== oldValue)) {
+        tracker.untrack(oldValue, element);
+      }
+
+      if (name === "name" && element.getAttributeNS(null, "id") !== oldValue) {
+        tracker.untrack(oldValue, element);
+      }
+
+      tracker.track(value, element);
+    }
+  }
+};
+
+exports.nodeAttachedToDocument = function (node) {
+  if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+    return;
+  }
+
+  const tracker = namedPropertiesTracker.get(node._ownerDocument._global);
+  if (!tracker) {
+    return;
+  }
+
+  tracker.track(node.getAttributeNS(null, "id"), node);
+
+  if (isNamedPropertyElement(node)) {
+    tracker.track(node.getAttributeNS(null, "name"), node);
+  }
+};
+
+exports.nodeDetachedFromDocument = function (node) {
+  if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+    return;
+  }
+
+  const tracker = namedPropertiesTracker.get(node._ownerDocument._global);
+  if (!tracker) {
+    return;
+  }
+
+  tracker.untrack(node.getAttributeNS(null, "id"), node);
+
+  if (isNamedPropertyElement(node)) {
+    tracker.untrack(node.getAttributeNS(null, "name"), node);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/MimeType-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/MimeType-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/MimeType-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3 @@
+"use strict";
+
+exports.implementation = class MimeType {};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/MimeTypeArray-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/MimeTypeArray-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/MimeTypeArray-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+
+exports.implementation = class MimeTypeArray {
+  get length() {
+    return 0;
+  }
+
+  item() {
+    return null;
+  }
+
+  namedItem() {
+    return null;
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    return [];
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/Navigator-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/Navigator-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/Navigator-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,29 @@
+"use strict";
+const { mixin } = require("../../utils");
+const PluginArray = require("../generated/PluginArray");
+const MimeTypeArray = require("../generated/MimeTypeArray");
+const NavigatorIDImpl = require("./NavigatorID-impl").implementation;
+const NavigatorLanguageImpl = require("./NavigatorLanguage-impl").implementation;
+const NavigatorOnLineImpl = require("./NavigatorOnLine-impl").implementation;
+const NavigatorCookiesImpl = require("./NavigatorCookies-impl").implementation;
+const NavigatorPluginsImpl = require("./NavigatorPlugins-impl").implementation;
+const NavigatorConcurrentHardwareImpl = require("./NavigatorConcurrentHardware-impl").implementation;
+
+class NavigatorImpl {
+  constructor(globalObject, args, privateData) {
+    this._globalObject = globalObject;
+    this.userAgent = privateData.userAgent;
+    this.languages = Object.freeze(["en-US", "en"]);
+    this.plugins = PluginArray.create(this._globalObject);
+    this.mimeTypes = MimeTypeArray.create(this._globalObject);
+  }
+}
+
+mixin(NavigatorImpl.prototype, NavigatorIDImpl.prototype);
+mixin(NavigatorImpl.prototype, NavigatorLanguageImpl.prototype);
+mixin(NavigatorImpl.prototype, NavigatorOnLineImpl.prototype);
+mixin(NavigatorImpl.prototype, NavigatorCookiesImpl.prototype);
+mixin(NavigatorImpl.prototype, NavigatorPluginsImpl.prototype);
+mixin(NavigatorImpl.prototype, NavigatorConcurrentHardwareImpl.prototype);
+
+exports.implementation = NavigatorImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorConcurrentHardware-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorConcurrentHardware-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorConcurrentHardware-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+"use strict";
+const os = require("os");
+
+exports.implementation = class NavigatorConcurrentHardwareImpl {
+  get hardwareConcurrency() {
+    return os.cpus().length;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorCookies-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorCookies-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorCookies-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,7 @@
+"use strict";
+
+exports.implementation = class NavigatorCookiesImpl {
+  get cookieEnabled() {
+    return true;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorID-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorID-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorID-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,37 @@
+"use strict";
+
+exports.implementation = class NavigatorIDImpl {
+  get appCodeName() {
+    return "Mozilla";
+  }
+
+  get appName() {
+    return "Netscape";
+  }
+
+  get appVersion() {
+    return "4.0";
+  }
+
+  get platform() {
+    return "";
+  }
+
+  get product() {
+    return "Gecko";
+  }
+
+  get productSub() {
+    return "20030107";
+  }
+
+  // see Navigator constructor for userAgent
+
+  get vendor() {
+    return "Apple Computer, Inc.";
+  }
+
+  get vendorSub() {
+    return "";
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorLanguage-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorLanguage-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorLanguage-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+exports.implementation = class NavigatorLanguageImpl {
+  get language() {
+    return "en-US";
+  }
+
+  // See Navigator constructor for languages
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorOnLine-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorOnLine-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorOnLine-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,7 @@
+"use strict";
+
+exports.implementation = class NavigatorOnLineImpl {
+  get onLine() {
+    return true;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorPlugins-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorPlugins-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/NavigatorPlugins-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+"use strict";
+
+exports.implementation = class NavigatorPluginsImpl {
+  // plugins and mimeTypes are implemented in Navigator-impl.js
+  javaEnabled() {
+    return false;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/Plugin-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/Plugin-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/Plugin-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,3 @@
+"use strict";
+
+exports.implementation = class Plugin {};
Index: frontend/node_modules/jsdom/lib/jsdom/living/navigator/PluginArray-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/navigator/PluginArray-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/navigator/PluginArray-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,23 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+
+exports.implementation = class PluginArray {
+  refresh() {}
+
+  get length() {
+    return 0;
+  }
+
+  item() {
+    return null;
+  }
+
+  namedItem() {
+    return null;
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    return [];
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/node-document-position.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/node-document-position.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/node-document-position.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,10 @@
+"use strict";
+
+module.exports = Object.freeze({
+  DOCUMENT_POSITION_DISCONNECTED: 1,
+  DOCUMENT_POSITION_PRECEDING: 2,
+  DOCUMENT_POSITION_FOLLOWING: 4,
+  DOCUMENT_POSITION_CONTAINS: 8,
+  DOCUMENT_POSITION_CONTAINED_BY: 16,
+  DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32
+});
Index: frontend/node_modules/jsdom/lib/jsdom/living/node-type.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/node-type.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/node-type.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+"use strict";
+
+module.exports = Object.freeze({
+  ELEMENT_NODE: 1,
+  ATTRIBUTE_NODE: 2,
+  TEXT_NODE: 3,
+  CDATA_SECTION_NODE: 4, // historical
+  ENTITY_REFERENCE_NODE: 5, // historical
+  ENTITY_NODE: 6, // historical
+  PROCESSING_INSTRUCTION_NODE: 7,
+  COMMENT_NODE: 8,
+  DOCUMENT_NODE: 9,
+  DOCUMENT_TYPE_NODE: 10,
+  DOCUMENT_FRAGMENT_NODE: 11,
+  NOTATION_NODE: 12 // historical
+});
Index: frontend/node_modules/jsdom/lib/jsdom/living/node.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/node.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/node.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,331 @@
+"use strict";
+const { appendAttribute } = require("./attributes");
+const NODE_TYPE = require("./node-type");
+
+const orderedSetParse = require("./helpers/ordered-set").parse;
+const { createElement } = require("./helpers/create-element");
+const { HTML_NS, XMLNS_NS } = require("./helpers/namespaces");
+const { cloningSteps, domSymbolTree } = require("./helpers/internal-constants");
+const { asciiCaseInsensitiveMatch, asciiLowercase } = require("./helpers/strings");
+
+const HTMLCollection = require("./generated/HTMLCollection");
+
+exports.clone = (node, document, cloneChildren) => {
+  if (document === undefined) {
+    document = node._ownerDocument;
+  }
+
+  let copy;
+  switch (node.nodeType) {
+    case NODE_TYPE.DOCUMENT_NODE:
+      // Can't use a simple `Document.createImpl` because of circular dependency issues :-/
+      copy = node._cloneDocument();
+      break;
+
+    case NODE_TYPE.DOCUMENT_TYPE_NODE:
+      copy = document.implementation.createDocumentType(node.name, node.publicId, node.systemId);
+      break;
+
+    case NODE_TYPE.ELEMENT_NODE:
+      copy = createElement(
+        document,
+        node._localName,
+        node._namespaceURI,
+        node._prefix,
+        node._isValue,
+        false
+      );
+
+      for (const attribute of node._attributeList) {
+        appendAttribute(copy, exports.clone(attribute, document));
+      }
+      break;
+
+    case NODE_TYPE.ATTRIBUTE_NODE:
+      copy = document._createAttribute({
+        namespace: node._namespace,
+        namespacePrefix: node._namespacePrefix,
+        localName: node._localName,
+        value: node._value
+      });
+      break;
+
+    case NODE_TYPE.TEXT_NODE:
+      copy = document.createTextNode(node._data);
+      break;
+
+    case NODE_TYPE.CDATA_SECTION_NODE:
+      copy = document.createCDATASection(node._data);
+      break;
+
+    case NODE_TYPE.COMMENT_NODE:
+      copy = document.createComment(node._data);
+      break;
+
+    case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+      copy = document.createProcessingInstruction(node.target, node._data);
+      break;
+
+    case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+      copy = document.createDocumentFragment();
+      break;
+  }
+
+  if (node[cloningSteps]) {
+    node[cloningSteps](copy, node, document, cloneChildren);
+  }
+
+  if (cloneChildren) {
+    for (const child of domSymbolTree.childrenIterator(node)) {
+      const childCopy = exports.clone(child, document, true);
+      copy._append(childCopy);
+    }
+  }
+
+  return copy;
+};
+
+// For the following, memoization is not applied here since the memoized results are stored on `this`.
+
+exports.listOfElementsWithClassNames = (classNames, root) => {
+  // https://dom.spec.whatwg.org/#concept-getElementsByClassName
+
+  const classes = orderedSetParse(classNames);
+
+  if (classes.size === 0) {
+    return HTMLCollection.createImpl(root._globalObject, [], { element: root, query: () => [] });
+  }
+
+  return HTMLCollection.createImpl(root._globalObject, [], {
+    element: root,
+    query: () => {
+      const isQuirksMode = root._ownerDocument.compatMode === "BackCompat";
+
+      return domSymbolTree.treeToArray(root, { filter(node) {
+        if (node.nodeType !== NODE_TYPE.ELEMENT_NODE || node === root) {
+          return false;
+        }
+
+        const { classList } = node;
+        if (isQuirksMode) {
+          for (const className of classes) {
+            if (!classList.tokenSet.some(cur => asciiCaseInsensitiveMatch(cur, className))) {
+              return false;
+            }
+          }
+        } else {
+          for (const className of classes) {
+            if (!classList.tokenSet.contains(className)) {
+              return false;
+            }
+          }
+        }
+
+        return true;
+      } });
+    }
+  });
+};
+
+exports.listOfElementsWithQualifiedName = (qualifiedName, root) => {
+  // https://dom.spec.whatwg.org/#concept-getelementsbytagname
+
+  if (qualifiedName === "*") {
+    return HTMLCollection.createImpl(root._globalObject, [], {
+      element: root,
+      query: () => domSymbolTree.treeToArray(root, {
+        filter: node => node.nodeType === NODE_TYPE.ELEMENT_NODE && node !== root
+      })
+    });
+  }
+
+  if (root._ownerDocument._parsingMode === "html") {
+    const lowerQualifiedName = asciiLowercase(qualifiedName);
+
+    return HTMLCollection.createImpl(root._globalObject, [], {
+      element: root,
+      query: () => domSymbolTree.treeToArray(root, {
+        filter(node) {
+          if (node.nodeType !== NODE_TYPE.ELEMENT_NODE || node === root) {
+            return false;
+          }
+
+          if (node._namespaceURI === HTML_NS) {
+            return node._qualifiedName === lowerQualifiedName;
+          }
+
+          return node._qualifiedName === qualifiedName;
+        }
+      })
+    });
+  }
+
+  return HTMLCollection.createImpl(root._globalObject, [], {
+    element: root,
+    query: () => domSymbolTree.treeToArray(root, {
+      filter(node) {
+        if (node.nodeType !== NODE_TYPE.ELEMENT_NODE || node === root) {
+          return false;
+        }
+
+        return node._qualifiedName === qualifiedName;
+      }
+    })
+  });
+};
+
+exports.listOfElementsWithNamespaceAndLocalName = (namespace, localName, root) => {
+  // https://dom.spec.whatwg.org/#concept-getelementsbytagnamens
+
+  if (namespace === "") {
+    namespace = null;
+  }
+
+  if (namespace === "*" && localName === "*") {
+    return HTMLCollection.createImpl(root._globalObject, [], {
+      element: root,
+      query: () => domSymbolTree.treeToArray(root, {
+        filter: node => node.nodeType === NODE_TYPE.ELEMENT_NODE && node !== root
+      })
+    });
+  }
+
+  if (namespace === "*") {
+    return HTMLCollection.createImpl(root._globalObject, [], {
+      element: root,
+      query: () => domSymbolTree.treeToArray(root, {
+        filter(node) {
+          if (node.nodeType !== NODE_TYPE.ELEMENT_NODE || node === root) {
+            return false;
+          }
+
+          return node._localName === localName;
+        }
+      })
+    });
+  }
+
+  if (localName === "*") {
+    return HTMLCollection.createImpl(root._globalObject, [], {
+      element: root,
+      query: () => domSymbolTree.treeToArray(root, {
+        filter(node) {
+          if (node.nodeType !== NODE_TYPE.ELEMENT_NODE || node === root) {
+            return false;
+          }
+
+          return node._namespaceURI === namespace;
+        }
+      })
+    });
+  }
+
+  return HTMLCollection.createImpl(root._globalObject, [], {
+    element: root,
+    query: () => domSymbolTree.treeToArray(root, {
+      filter(node) {
+        if (node.nodeType !== NODE_TYPE.ELEMENT_NODE || node === root) {
+          return false;
+        }
+
+        return node._localName === localName && node._namespaceURI === namespace;
+      }
+    })
+  });
+};
+
+// https://dom.spec.whatwg.org/#converting-nodes-into-a-node
+// create a fragment (or just return a node for one item)
+exports.convertNodesIntoNode = (document, nodes) => {
+  if (nodes.length === 1) { // note: I'd prefer to check instanceof Node rather than string
+    return typeof nodes[0] === "string" ? document.createTextNode(nodes[0]) : nodes[0];
+  }
+  const fragment = document.createDocumentFragment();
+  for (let i = 0; i < nodes.length; i++) {
+    fragment._append(typeof nodes[i] === "string" ? document.createTextNode(nodes[i]) : nodes[i]);
+  }
+  return fragment;
+};
+
+// https://dom.spec.whatwg.org/#locate-a-namespace-prefix
+exports.locateNamespacePrefix = (element, namespace) => {
+  if (element._namespaceURI === namespace && element._prefix !== null) {
+    return element._prefix;
+  }
+
+  for (const attribute of element._attributeList) {
+    if (attribute._namespacePrefix === "xmlns" && attribute._value === namespace) {
+      return attribute._localName;
+    }
+  }
+
+  if (element.parentElement !== null) {
+    return exports.locateNamespacePrefix(element.parentElement, namespace);
+  }
+
+  return null;
+};
+
+// https://dom.spec.whatwg.org/#locate-a-namespace
+exports.locateNamespace = (node, prefix) => {
+  switch (node.nodeType) {
+    case NODE_TYPE.ELEMENT_NODE: {
+      if (node._namespaceURI !== null && node._prefix === prefix) {
+        return node._namespaceURI;
+      }
+
+      if (prefix === null) {
+        for (const attribute of node._attributeList) {
+          if (attribute._namespace === XMLNS_NS &&
+              attribute._namespacePrefix === null &&
+              attribute._localName === "xmlns") {
+            return attribute._value !== "" ? attribute._value : null;
+          }
+        }
+      } else {
+        for (const attribute of node._attributeList) {
+          if (attribute._namespace === XMLNS_NS &&
+              attribute._namespacePrefix === "xmlns" &&
+              attribute._localName === prefix) {
+            return attribute._value !== "" ? attribute._value : null;
+          }
+        }
+      }
+
+      if (node.parentElement === null) {
+        return null;
+      }
+
+      return exports.locateNamespace(node.parentElement, prefix);
+    }
+
+    case NODE_TYPE.DOCUMENT_NODE: {
+      if (node.documentElement === null) {
+        return null;
+      }
+
+      return exports.locateNamespace(node.documentElement, prefix);
+    }
+
+    case NODE_TYPE.DOCUMENT_TYPE_NODE:
+    case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+      return null;
+    }
+
+    case NODE_TYPE.ATTRIBUTE_NODE: {
+      if (node._element === null) {
+        return null;
+      }
+
+      return exports.locateNamespace(node._element, prefix);
+    }
+
+    default: {
+      if (node.parentElement === null) {
+        return null;
+      }
+
+      return exports.locateNamespace(node.parentElement, prefix);
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/CDATASection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+"use strict";
+
+const TextImpl = require("./Text-impl").implementation;
+const NODE_TYPE = require("../node-type");
+
+class CDATASectionImpl extends TextImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this.nodeType = NODE_TYPE.CDATA_SECTION_NODE;
+  }
+}
+
+module.exports = {
+  implementation: CDATASectionImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/CharacterData-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,118 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const { mixin } = require("../../utils");
+const NodeImpl = require("./Node-impl").implementation;
+const ChildNodeImpl = require("./ChildNode-impl").implementation;
+const NonDocumentTypeChildNodeImpl = require("./NonDocumentTypeChildNode-impl").implementation;
+
+const { TEXT_NODE } = require("../node-type");
+const { MUTATION_TYPE, queueMutationRecord } = require("../helpers/mutation-observers");
+
+// https://dom.spec.whatwg.org/#characterdata
+class CharacterDataImpl extends NodeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._data = privateData.data;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-data
+  get data() {
+    return this._data;
+  }
+  set data(data) {
+    this.replaceData(0, this.length, data);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-length
+  get length() {
+    return this._data.length;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-substringdata
+  // https://dom.spec.whatwg.org/#concept-cd-substring
+  substringData(offset, count) {
+    const { length } = this;
+
+    if (offset > length) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+
+    if (offset + count > length) {
+      return this._data.slice(offset);
+    }
+
+    return this._data.slice(offset, offset + count);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-appenddata
+  appendData(data) {
+    this.replaceData(this.length, 0, data);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-insertdata
+  insertData(offset, data) {
+    this.replaceData(offset, 0, data);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-deletedata
+  deleteData(offset, count) {
+    this.replaceData(offset, count, "");
+  }
+
+  // https://dom.spec.whatwg.org/#dom-characterdata-replacedata
+  // https://dom.spec.whatwg.org/#concept-cd-replace
+  replaceData(offset, count, data) {
+    const { length } = this;
+
+    if (offset > length) {
+      throw DOMException.create(this._globalObject, [
+        "The index is not in the allowed range.",
+        "IndexSizeError"
+      ]);
+    }
+
+    if (offset + count > length) {
+      count = length - offset;
+    }
+
+    queueMutationRecord(MUTATION_TYPE.CHARACTER_DATA, this, null, null, this._data, [], [], null, null);
+
+    const start = this._data.slice(0, offset);
+    const end = this._data.slice(offset + count);
+    this._data = start + data + end;
+
+    for (const range of this._referencedRanges) {
+      const { _start, _end } = range;
+
+      if (_start.offset > offset && _start.offset <= offset + count) {
+        range._setLiveRangeStart(this, offset);
+      }
+
+      if (_end.offset > offset && _end.offset <= offset + count) {
+        range._setLiveRangeEnd(this, offset);
+      }
+
+      if (_start.offset > offset + count) {
+        range._setLiveRangeStart(this, _start.offset + data.length - count);
+      }
+
+      if (_end.offset > offset + count) {
+        range._setLiveRangeEnd(this, _end.offset + data.length - count);
+      }
+    }
+
+    if (this.nodeType === TEXT_NODE && this.parentNode) {
+      this.parentNode._childTextContentChangeSteps();
+    }
+  }
+}
+
+mixin(CharacterDataImpl.prototype, NonDocumentTypeChildNodeImpl.prototype);
+mixin(CharacterDataImpl.prototype, ChildNodeImpl.prototype);
+
+module.exports = {
+  implementation: CharacterDataImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/ChildNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,80 @@
+"use strict";
+
+const { convertNodesIntoNode } = require("../node");
+
+class ChildNodeImpl {
+  remove() {
+    if (!this.parentNode) {
+      return;
+    }
+
+    this.parentNode._remove(this);
+  }
+
+  after(...nodes) {
+    const parent = this.parentNode;
+    if (parent) {
+      let viableNextSibling = this.nextSibling;
+      let idx = viableNextSibling ? nodes.indexOf(viableNextSibling) : -1;
+
+      while (idx !== -1) {
+        viableNextSibling = viableNextSibling.nextSibling;
+        if (!viableNextSibling) {
+          break;
+        }
+        idx = nodes.indexOf(viableNextSibling);
+      }
+
+      parent._preInsert(convertNodesIntoNode(this._ownerDocument, nodes), viableNextSibling);
+    }
+  }
+
+  before(...nodes) {
+    const parent = this.parentNode;
+    if (parent) {
+      let viablePreviousSibling = this.previousSibling;
+      let idx = viablePreviousSibling ? nodes.indexOf(viablePreviousSibling) : -1;
+
+      while (idx !== -1) {
+        viablePreviousSibling = viablePreviousSibling.previousSibling;
+        if (!viablePreviousSibling) {
+          break;
+        }
+        idx = nodes.indexOf(viablePreviousSibling);
+      }
+
+      parent._preInsert(
+        convertNodesIntoNode(this._ownerDocument, nodes),
+        viablePreviousSibling ? viablePreviousSibling.nextSibling : parent.firstChild
+      );
+    }
+  }
+
+  replaceWith(...nodes) {
+    const parent = this.parentNode;
+    if (parent) {
+      let viableNextSibling = this.nextSibling;
+      let idx = viableNextSibling ? nodes.indexOf(viableNextSibling) : -1;
+
+      while (idx !== -1) {
+        viableNextSibling = viableNextSibling.nextSibling;
+        if (!viableNextSibling) {
+          break;
+        }
+        idx = nodes.indexOf(viableNextSibling);
+      }
+
+      const node = convertNodesIntoNode(this._ownerDocument, nodes);
+
+      if (this.parentNode === parent) {
+        parent._replace(node, this);
+      } else {
+        parent._preInsert(node, viableNextSibling);
+      }
+    }
+  }
+}
+
+module.exports = {
+  implementation: ChildNodeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/Comment-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+"use strict";
+const CharacterDataImpl = require("./CharacterData-impl").implementation;
+const idlUtils = require("../generated/utils");
+const NODE_TYPE = require("../node-type");
+
+class CommentImpl extends CharacterDataImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, {
+      data: args[0],
+      ownerDocument: idlUtils.implForWrapper(globalObject._document),
+      ...privateData
+    });
+
+    this.nodeType = NODE_TYPE.COMMENT_NODE;
+  }
+}
+
+module.exports = {
+  implementation: CommentImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMImplementation-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,120 @@
+"use strict";
+
+const validateNames = require("../helpers/validate-names");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const { createElement, internalCreateElementNSSteps } = require("../helpers/create-element");
+const DocumentType = require("../generated/DocumentType");
+const documents = require("../documents.js");
+
+class DOMImplementationImpl {
+  constructor(globalObject, args, privateData) {
+    this._globalObject = globalObject;
+    this._ownerDocument = privateData.ownerDocument;
+  }
+
+  hasFeature() {
+    return true;
+  }
+
+  createDocumentType(qualifiedName, publicId, systemId) {
+    validateNames.qname(this._globalObject, qualifiedName);
+
+    return DocumentType.createImpl(this._globalObject, [], {
+      ownerDocument: this._ownerDocument,
+      name: qualifiedName,
+      publicId,
+      systemId
+    });
+  }
+
+  // https://dom.spec.whatwg.org/#dom-domimplementation-createdocument
+  createDocument(namespace, qualifiedName, doctype) {
+    let contentType = "application/xml";
+
+    if (namespace === HTML_NS) {
+      contentType = "application/xhtml+xml";
+    } else if (namespace === SVG_NS) {
+      contentType = "image/svg+xml";
+    }
+
+    const document = documents.createImpl(this._globalObject, {
+      contentType,
+      parsingMode: "xml",
+      encoding: "UTF-8"
+    });
+
+    let element = null;
+    if (qualifiedName !== "") {
+      element = internalCreateElementNSSteps(document, namespace, qualifiedName, {});
+    }
+
+    if (doctype !== null) {
+      document.appendChild(doctype);
+    }
+
+    if (element !== null) {
+      document.appendChild(element);
+    }
+
+    document._origin = this._ownerDocument._origin;
+
+    return document;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument
+  createHTMLDocument(title) {
+    // Let doc be a new document that is an HTML document.
+    // Set doc's content type to "text/html".
+    const document = documents.createImpl(this._globalObject, {
+      parsingMode: "html",
+      encoding: "UTF-8"
+    });
+
+    // Create a doctype, with "html" as its name and with its node document set
+    // to doc. Append the newly created node to doc.
+    const doctype = DocumentType.createImpl(this._globalObject, [], {
+      ownerDocument: document,
+      name: "html",
+      publicId: "",
+      systemId: ""
+    });
+
+    document.appendChild(doctype);
+
+    // Create an html element in the HTML namespace, and append it to doc.
+    const htmlElement = createElement(document, "html", HTML_NS);
+    document.appendChild(htmlElement);
+
+    // Create a head element in the HTML namespace, and append it to the html
+    // element created in the previous step.
+    const headElement = createElement(document, "head", HTML_NS);
+    htmlElement.appendChild(headElement);
+
+    // If the title argument is not omitted:
+    if (title !== undefined) {
+      // Create a title element in the HTML namespace, and append it to the head
+      // element created in the previous step.
+      const titleElement = createElement(document, "title", HTML_NS);
+      headElement.appendChild(titleElement);
+
+      // Create a Text node, set its data to title (which could be the empty
+      // string), and append it to the title element created in the previous step.
+      titleElement.appendChild(document.createTextNode(title));
+    }
+
+    // Create a body element in the HTML namespace, and append it to the html
+    // element created in the earlier step.
+    const bodyElement = createElement(document, "body", HTML_NS);
+    htmlElement.appendChild(bodyElement);
+
+    // doc's origin is an alias to the origin of the context object's associated
+    // document, and doc's effective script origin is an alias to the effective
+    // script origin of the context object's associated document.
+
+    return document;
+  }
+}
+
+module.exports = {
+  implementation: DOMImplementationImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMStringMap-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+const { setAttributeValue, removeAttributeByName } = require("../attributes");
+const validateName = require("../helpers/validate-names").name;
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const dataAttrRe = /^data-([^A-Z]*)$/;
+
+function attrCamelCase(name) {
+  return name.replace(/-([a-z])/g, (match, alpha) => alpha.toUpperCase());
+}
+
+function attrSnakeCase(name) {
+  return name.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
+}
+
+exports.implementation = class DOMStringMapImpl {
+  constructor(globalObject, args, privateData) {
+    this._globalObject = globalObject;
+    this._element = privateData.element;
+  }
+  get [idlUtils.supportedPropertyNames]() {
+    const result = new Set();
+    const { attributes } = this._element;
+    for (let i = 0; i < attributes.length; i++) {
+      const attr = attributes.item(i);
+      const matches = dataAttrRe.exec(attr.localName);
+      if (matches) {
+        result.add(attrCamelCase(matches[1]));
+      }
+    }
+    return result;
+  }
+  [idlUtils.namedGet](name) {
+    const { attributes } = this._element;
+    for (let i = 0; i < attributes.length; i++) {
+      const attr = attributes.item(i);
+      const matches = dataAttrRe.exec(attr.localName);
+      if (matches && attrCamelCase(matches[1]) === name) {
+        return attr.value;
+      }
+    }
+    return undefined;
+  }
+  [idlUtils.namedSetNew](name, value) {
+    if (/-[a-z]/.test(name)) {
+      throw DOMException.create(this._globalObject, [
+        `'${name}' is not a valid property name`,
+        "SyntaxError"
+      ]);
+    }
+    name = `data-${attrSnakeCase(name)}`;
+    validateName(this._globalObject, name);
+    setAttributeValue(this._element, name, value);
+  }
+  [idlUtils.namedSetExisting](name, value) {
+    this[idlUtils.namedSetNew](name, value);
+  }
+  [idlUtils.namedDelete](name) {
+    name = `data-${attrSnakeCase(name)}`;
+    removeAttributeByName(this._element, name);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/DOMTokenList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,171 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const OrderedSet = require("../helpers/ordered-set.js");
+const { asciiLowercase } = require("../helpers/strings.js");
+const idlUtils = require("../generated/utils.js");
+
+const { getAttributeValue, setAttributeValue, hasAttributeByName } = require("../attributes.js");
+
+function validateTokens(globalObject, ...tokens) {
+  for (const token of tokens) {
+    if (token === "") {
+      throw DOMException.create(globalObject, ["The token provided must not be empty.", "SyntaxError"]);
+    }
+  }
+  for (const token of tokens) {
+    if (/[\t\n\f\r ]/.test(token)) {
+      throw DOMException.create(globalObject, [
+        "The token provided contains HTML space characters, which are not valid in tokens.",
+        "InvalidCharacterError"
+      ]);
+    }
+  }
+}
+
+// https://dom.spec.whatwg.org/#domtokenlist
+class DOMTokenListImpl {
+  constructor(globalObject, args, privateData) {
+    this._globalObject = globalObject;
+
+    // _syncWithElement() must always be called before any _tokenSet access.
+    this._tokenSet = new OrderedSet();
+    this._element = privateData.element;
+    this._attributeLocalName = privateData.attributeLocalName;
+    this._supportedTokens = privateData.supportedTokens;
+
+    // Needs synchronization with element if token set is to be accessed.
+    this._dirty = true;
+  }
+
+  attrModified() {
+    this._dirty = true;
+  }
+
+  _syncWithElement() {
+    if (!this._dirty) {
+      return;
+    }
+
+    const val = getAttributeValue(this._element, this._attributeLocalName);
+    if (val === null) {
+      this._tokenSet.empty();
+    } else {
+      this._tokenSet = OrderedSet.parse(val);
+    }
+
+    this._dirty = false;
+  }
+
+  _validationSteps(token) {
+    if (!this._supportedTokens) {
+      throw new TypeError(`${this._attributeLocalName} attribute has no supported tokens`);
+    }
+    const lowerToken = asciiLowercase(token);
+    return this._supportedTokens.has(lowerToken);
+  }
+
+  _updateSteps() {
+    if (!hasAttributeByName(this._element, this._attributeLocalName) && this._tokenSet.isEmpty()) {
+      return;
+    }
+    setAttributeValue(this._element, this._attributeLocalName, this._tokenSet.serialize());
+  }
+
+  _serializeSteps() {
+    return getAttributeValue(this._element, this._attributeLocalName);
+  }
+
+  // Used by other parts of jsdom
+  get tokenSet() {
+    this._syncWithElement();
+    return this._tokenSet;
+  }
+
+  get length() {
+    this._syncWithElement();
+    return this._tokenSet.size;
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    this._syncWithElement();
+    return this._tokenSet.keys();
+  }
+
+  item(index) {
+    this._syncWithElement();
+    if (index >= this._tokenSet.size) {
+      return null;
+    }
+    return this._tokenSet.get(index);
+  }
+
+  contains(token) {
+    this._syncWithElement();
+    return this._tokenSet.contains(token);
+  }
+
+  add(...tokens) {
+    for (const token of tokens) {
+      validateTokens(this._globalObject, token);
+    }
+    this._syncWithElement();
+    for (const token of tokens) {
+      this._tokenSet.append(token);
+    }
+    this._updateSteps();
+  }
+
+  remove(...tokens) {
+    for (const token of tokens) {
+      validateTokens(this._globalObject, token);
+    }
+    this._syncWithElement();
+    this._tokenSet.remove(...tokens);
+    this._updateSteps();
+  }
+
+  toggle(token, force = undefined) {
+    validateTokens(this._globalObject, token);
+    this._syncWithElement();
+    if (this._tokenSet.contains(token)) {
+      if (force === undefined || force === false) {
+        this._tokenSet.remove(token);
+        this._updateSteps();
+        return false;
+      }
+      return true;
+    }
+    if (force === undefined || force === true) {
+      this._tokenSet.append(token);
+      this._updateSteps();
+      return true;
+    }
+    return false;
+  }
+
+  replace(token, newToken) {
+    validateTokens(this._globalObject, token, newToken);
+    this._syncWithElement();
+    if (!this._tokenSet.contains(token)) {
+      return false;
+    }
+    this._tokenSet.replace(token, newToken);
+    this._updateSteps();
+    return true;
+  }
+
+  supports(token) {
+    return this._validationSteps(token);
+  }
+
+  get value() {
+    return this._serializeSteps();
+  }
+
+  set value(V) {
+    setAttributeValue(this._element, this._attributeLocalName, V);
+  }
+}
+
+exports.implementation = DOMTokenListImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,946 @@
+"use strict";
+
+const { CookieJar } = require("tough-cookie");
+
+const NodeImpl = require("./Node-impl").implementation;
+const idlUtils = require("../generated/utils");
+const NODE_TYPE = require("../node-type");
+const { hasWeakRefs, mixin, memoizeQuery } = require("../../utils");
+const { firstChildWithLocalName, firstChildWithLocalNames, firstDescendantWithLocalName } =
+  require("../helpers/traversal");
+const whatwgURL = require("whatwg-url");
+const StyleSheetList = require("../generated/StyleSheetList.js");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const eventAccessors = require("../helpers/create-event-accessor");
+const { asciiLowercase, stripAndCollapseASCIIWhitespace } = require("../helpers/strings");
+const { childTextContent } = require("../helpers/text");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { parseIntoDocument } = require("../../browser/parser");
+const History = require("../generated/History");
+const Location = require("../generated/Location");
+const HTMLCollection = require("../generated/HTMLCollection");
+const NodeList = require("../generated/NodeList");
+const validateName = require("../helpers/validate-names").name;
+const { validateAndExtract } = require("../helpers/validate-names");
+const { fireAnEvent } = require("../helpers/events");
+const { shadowIncludingInclusiveDescendantsIterator } = require("../helpers/shadow-dom");
+const { enqueueCECallbackReaction } = require("../helpers/custom-elements");
+const { createElement, internalCreateElementNSSteps } = require("../helpers/create-element");
+const IterableWeakSet = require("../helpers/iterable-weak-set");
+
+const DocumentOrShadowRootImpl = require("./DocumentOrShadowRoot-impl").implementation;
+const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
+const NonElementParentNodeImpl = require("./NonElementParentNode-impl").implementation;
+const ParentNodeImpl = require("./ParentNode-impl").implementation;
+
+const { clone, listOfElementsWithQualifiedName, listOfElementsWithNamespaceAndLocalName,
+  listOfElementsWithClassNames } = require("../node");
+const generatedAttr = require("../generated/Attr");
+const Comment = require("../generated/Comment");
+const ProcessingInstruction = require("../generated/ProcessingInstruction");
+const CDATASection = require("../generated/CDATASection");
+const Text = require("../generated/Text");
+const DocumentFragment = require("../generated/DocumentFragment");
+const DOMImplementation = require("../generated/DOMImplementation");
+const TreeWalker = require("../generated/TreeWalker");
+const NodeIterator = require("../generated/NodeIterator");
+const ShadowRoot = require("../generated/ShadowRoot");
+const Range = require("../generated/Range");
+const documents = require("../documents.js");
+
+const CustomEvent = require("../generated/CustomEvent");
+const ErrorEvent = require("../generated/ErrorEvent");
+const Event = require("../generated/Event");
+const FocusEvent = require("../generated/FocusEvent");
+const HashChangeEvent = require("../generated/HashChangeEvent");
+const KeyboardEvent = require("../generated/KeyboardEvent");
+const MessageEvent = require("../generated/MessageEvent");
+const MouseEvent = require("../generated/MouseEvent");
+const PopStateEvent = require("../generated/PopStateEvent");
+const ProgressEvent = require("../generated/ProgressEvent");
+const TouchEvent = require("../generated/TouchEvent");
+const UIEvent = require("../generated/UIEvent");
+
+const RequestManager = require("../../browser/resources/request-manager");
+const AsyncResourceQueue = require("../../browser/resources/async-resource-queue");
+const ResourceQueue = require("../../browser/resources/resource-queue");
+const PerDocumentResourceLoader = require("../../browser/resources/per-document-resource-loader");
+
+function clearChildNodes(node) {
+  for (let child = domSymbolTree.firstChild(node); child; child = domSymbolTree.firstChild(node)) {
+    node.removeChild(child);
+  }
+}
+
+function pad(number) {
+  if (number < 10) {
+    return "0" + number;
+  }
+  return number;
+}
+
+function toLastModifiedString(date) {
+  return pad(date.getMonth() + 1) +
+    "/" + pad(date.getDate()) +
+    "/" + date.getFullYear() +
+    " " + pad(date.getHours()) +
+    ":" + pad(date.getMinutes()) +
+    ":" + pad(date.getSeconds());
+}
+
+const eventInterfaceTable = {
+  customevent: CustomEvent,
+  errorevent: ErrorEvent,
+  event: Event,
+  events: Event,
+  focusevent: FocusEvent,
+  hashchangeevent: HashChangeEvent,
+  htmlevents: Event,
+  keyboardevent: KeyboardEvent,
+  messageevent: MessageEvent,
+  mouseevent: MouseEvent,
+  mouseevents: MouseEvent,
+  popstateevent: PopStateEvent,
+  progressevent: ProgressEvent,
+  svgevents: Event,
+  touchevent: TouchEvent,
+  uievent: UIEvent,
+  uievents: UIEvent
+};
+
+class DocumentImpl extends NodeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._initGlobalEvents();
+
+    this._ownerDocument = this;
+    this.nodeType = NODE_TYPE.DOCUMENT_NODE;
+    if (!privateData.options) {
+      privateData.options = {};
+    }
+    if (!privateData.options.parsingMode) {
+      privateData.options.parsingMode = "xml";
+    }
+    if (!privateData.options.encoding) {
+      privateData.options.encoding = "UTF-8";
+    }
+    if (!privateData.options.contentType) {
+      privateData.options.contentType = privateData.options.parsingMode === "xml" ? "application/xml" : "text/html";
+    }
+
+    this._parsingMode = privateData.options.parsingMode;
+
+    this._implementation = DOMImplementation.createImpl(this._globalObject, [], {
+      ownerDocument: this
+    });
+
+    this._defaultView = privateData.options.defaultView || null;
+    this._global = privateData.options.global;
+    this._ids = Object.create(null);
+    this._attached = true;
+    this._currentScript = null;
+    this._pageShowingFlag = false;
+    this._cookieJar = privateData.options.cookieJar;
+    this._parseOptions = privateData.options.parseOptions || {};
+    this._scriptingDisabled = privateData.options.scriptingDisabled;
+    if (this._cookieJar === undefined) {
+      this._cookieJar = new CookieJar(null, { looseMode: true });
+    }
+
+    if (this._scriptingDisabled) {
+      this._parseOptions.scriptingEnabled = false;
+    }
+
+    this.contentType = privateData.options.contentType;
+    this._encoding = privateData.options.encoding;
+
+    const urlOption = privateData.options.url === undefined ? "about:blank" : privateData.options.url;
+    const parsed = whatwgURL.parseURL(urlOption);
+    if (parsed === null) {
+      throw new TypeError(`Could not parse "${urlOption}" as a URL`);
+    }
+
+    this._URL = parsed;
+    this._origin = urlOption === "about:blank" && privateData.options.parentOrigin ?
+      privateData.options.parentOrigin :
+      whatwgURL.serializeURLOrigin(this._URL);
+
+    this._location = Location.createImpl(this._globalObject, [], { relevantDocument: this });
+    this._history = History.createImpl(this._globalObject, [], {
+      window: this._defaultView,
+      document: this,
+      actAsIfLocationReloadCalled: () => this._location.reload()
+    });
+
+    if (hasWeakRefs) {
+      this._workingNodeIterators = new IterableWeakSet();
+    } else {
+      this._workingNodeIterators = [];
+    }
+
+    this._referrer = privateData.options.referrer || "";
+    this._lastModified = toLastModifiedString(privateData.options.lastModified || new Date());
+    this._asyncQueue = new AsyncResourceQueue();
+    this._queue = new ResourceQueue({ asyncQueue: this._asyncQueue, paused: false });
+    this._deferQueue = new ResourceQueue({ paused: true });
+    this._requestManager = new RequestManager();
+    this._currentDocumentReadiness = privateData.options.readyState || "loading";
+
+    this._lastFocusedElement = null;
+
+    this._resourceLoader = new PerDocumentResourceLoader(this);
+
+    // Each Document in a browsing context can also have a latest entry. This is the entry for that Document
+    // to which the browsing context's session history was most recently traversed. When a Document is created,
+    // it initially has no latest entry.
+    this._latestEntry = null;
+
+    // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter
+    this._throwOnDynamicMarkupInsertionCounter = 0;
+  }
+
+  _getTheParent(event) {
+    if (event.type === "load" || !this._defaultView) {
+      return null;
+    }
+
+    return idlUtils.implForWrapper(this._defaultView);
+  }
+
+  get compatMode() {
+    return this._parsingMode === "xml" || this.doctype ? "CSS1Compat" : "BackCompat";
+  }
+  get charset() {
+    return this._encoding;
+  }
+  get characterSet() {
+    return this._encoding;
+  }
+  get inputEncoding() {
+    return this._encoding;
+  }
+  get doctype() {
+    for (const childNode of domSymbolTree.childrenIterator(this)) {
+      if (childNode.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
+        return childNode;
+      }
+    }
+    return null;
+  }
+  get URL() {
+    return whatwgURL.serializeURL(this._URL);
+  }
+  get documentURI() {
+    return whatwgURL.serializeURL(this._URL);
+  }
+  get location() {
+    return this._defaultView ? this._location : null;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-document-documentelement
+  get documentElement() {
+    for (const childNode of domSymbolTree.childrenIterator(this)) {
+      if (childNode.nodeType === NODE_TYPE.ELEMENT_NODE) {
+        return childNode;
+      }
+    }
+
+    return null;
+  }
+
+  get implementation() {
+    return this._implementation;
+  }
+  set implementation(implementation) {
+    this._implementation = implementation;
+  }
+
+  get defaultView() {
+    return this._defaultView;
+  }
+
+  get currentScript() {
+    return this._currentScript;
+  }
+
+  get readyState() {
+    return this._currentDocumentReadiness;
+  }
+
+  set readyState(state) {
+    this._currentDocumentReadiness = state;
+    fireAnEvent("readystatechange", this);
+  }
+
+  hasFocus() {
+    return Boolean(this._lastFocusedElement);
+  }
+
+  _descendantRemoved(parent, child) {
+    if (child.tagName === "STYLE") {
+      this.styleSheets._remove(child.sheet);
+    }
+
+    super._descendantRemoved(parent, child);
+  }
+
+  write(...args) {
+    let text = "";
+    for (let i = 0; i < args.length; ++i) {
+      text += args[i];
+    }
+
+    if (this._parsingMode === "xml") {
+      throw DOMException.create(this._globalObject, [
+        "Cannot use document.write on XML documents",
+        "InvalidStateError"
+      ]);
+    }
+
+    if (this._throwOnDynamicMarkupInsertionCounter > 0) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot use document.write while a custom element upgrades",
+        "InvalidStateError"
+      ]);
+    }
+
+    if (this._writeAfterElement) {
+      // If called from an script element directly (during the first tick),
+      // the new elements are inserted right after that element.
+      const tempDiv = this.createElement("div");
+      tempDiv.innerHTML = text;
+
+      let child = tempDiv.firstChild;
+      let previous = this._writeAfterElement;
+      const parent = this._writeAfterElement.parentNode;
+
+      while (child) {
+        const node = child;
+        child = child.nextSibling;
+
+        node._isMovingDueToDocumentWrite = true; // hack for script execution
+        parent.insertBefore(node, previous.nextSibling);
+        node._isMovingDueToDocumentWrite = false;
+
+        previous = node;
+      }
+    } else if (this.readyState === "loading") {
+      // During page loading, document.write appends to the current element
+      // Find the last child that has been added to the document.
+      if (this.lastChild) {
+        let node = this;
+        while (node.lastChild && node.lastChild.nodeType === NODE_TYPE.ELEMENT_NODE) {
+          node = node.lastChild;
+        }
+        node.innerHTML = text;
+      } else {
+        clearChildNodes(this);
+        parseIntoDocument(text, this);
+      }
+    } else if (text) {
+      clearChildNodes(this);
+      parseIntoDocument(text, this);
+    }
+  }
+
+  writeln(...args) {
+    this.write(...args, "\n");
+  }
+
+  // This is implemented separately for Document (which has a _ids cache) and DocumentFragment (which does not).
+  getElementById(id) {
+    if (!this._ids[id]) {
+      return null;
+    }
+
+    // Let's find the first element with where it's root is the document.
+    const matchElement = this._ids[id].find(candidate => {
+      let root = candidate;
+      while (domSymbolTree.parent(root)) {
+        root = domSymbolTree.parent(root);
+      }
+
+      return root === this;
+    });
+
+    return matchElement || null;
+  }
+
+  get referrer() {
+    return this._referrer || "";
+  }
+  get lastModified() {
+    return this._lastModified;
+  }
+  get images() {
+    return this.getElementsByTagName("IMG");
+  }
+  get embeds() {
+    return this.getElementsByTagName("EMBED");
+  }
+  get plugins() {
+    return this.embeds;
+  }
+  get links() {
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => domSymbolTree.treeToArray(this, {
+        filter: node => (node._localName === "a" || node._localName === "area") &&
+                        node.hasAttributeNS(null, "href") &&
+                        node._namespaceURI === HTML_NS
+      })
+    });
+  }
+  get forms() {
+    return this.getElementsByTagName("FORM");
+  }
+  get scripts() {
+    return this.getElementsByTagName("SCRIPT");
+  }
+  get anchors() {
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => domSymbolTree.treeToArray(this, {
+        filter: node => node._localName === "a" &&
+                        node.hasAttributeNS(null, "name") &&
+                        node._namespaceURI === HTML_NS
+      })
+    });
+  }
+
+  // The applets attribute must return an
+  // HTMLCollection rooted at the Document node,
+  // whose filter matches nothing.
+  // (It exists for historical reasons.)
+  get applets() {
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => []
+    });
+  }
+
+  open() {
+    let child = domSymbolTree.firstChild(this);
+    while (child) {
+      this.removeChild(child);
+      child = domSymbolTree.firstChild(this);
+    }
+    this._modified();
+    return this;
+  }
+  close(noQueue) {
+    // In some cases like when creating an empty iframe, I want to emit the
+    // events right away to avoid problems if later I asign the property src.
+    if (noQueue) {
+      this.readyState = "complete";
+
+      fireAnEvent("DOMContentLoaded", this, undefined, { bubbles: true });
+      fireAnEvent("load", this);
+
+      return;
+    }
+    this._queue.resume();
+
+    const dummyPromise = Promise.resolve();
+
+    const onDOMContentLoad = () => {
+      const doc = this;
+      function dispatchEvent() {
+        // https://html.spec.whatwg.org/#the-end
+        doc.readyState = "interactive";
+        fireAnEvent("DOMContentLoaded", doc, undefined, { bubbles: true });
+      }
+
+      return new Promise(resolve => {
+        if (!this._deferQueue.tail) {
+          dispatchEvent();
+          resolve();
+          return;
+        }
+
+        this._deferQueue.setListener(() => {
+          dispatchEvent();
+          resolve();
+        });
+
+        this._deferQueue.resume();
+      });
+    };
+
+    const onLoad = () => {
+      const doc = this;
+      function dispatchEvent() {
+        doc.readyState = "complete";
+        fireAnEvent("load", doc);
+      }
+
+      return new Promise(resolve => {
+        if (this._asyncQueue.count() === 0) {
+          dispatchEvent();
+          resolve();
+          return;
+        }
+
+        this._asyncQueue.setListener(() => {
+          dispatchEvent();
+          resolve();
+        });
+      });
+    };
+
+    this._queue.push(dummyPromise, onDOMContentLoad, null);
+    // Set the readyState to 'complete' once all resources are loaded.
+    // As a side-effect the document's load-event will be dispatched.
+    this._queue.push(dummyPromise, onLoad, null, true);
+  }
+
+  getElementsByName(elementName) {
+    return NodeList.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => domSymbolTree.treeToArray(this, {
+        filter: node => node.getAttributeNS && node.getAttributeNS(null, "name") === elementName
+      })
+    });
+  }
+
+  get title() {
+    const { documentElement } = this;
+    let value = "";
+
+    if (documentElement && documentElement._localName === "svg") {
+      const svgTitleElement = firstChildWithLocalName(documentElement, "title", SVG_NS);
+
+      if (svgTitleElement) {
+        value = childTextContent(svgTitleElement);
+      }
+    } else {
+      const titleElement = firstDescendantWithLocalName(this, "title");
+
+      if (titleElement) {
+        value = childTextContent(titleElement);
+      }
+    }
+
+    value = stripAndCollapseASCIIWhitespace(value);
+
+    return value;
+  }
+
+  set title(value) {
+    const { documentElement } = this;
+    let element;
+
+    if (documentElement && documentElement._localName === "svg") {
+      element = firstChildWithLocalName(documentElement, "title", SVG_NS);
+
+      if (!element) {
+        element = this.createElementNS(SVG_NS, "title");
+
+        this._insert(element, documentElement.firstChild);
+      }
+
+      element.textContent = value;
+    } else if (documentElement && documentElement._namespaceURI === HTML_NS) {
+      const titleElement = firstDescendantWithLocalName(this, "title");
+      const headElement = this.head;
+
+      if (titleElement === null && headElement === null) {
+        return;
+      }
+
+      if (titleElement !== null) {
+        element = titleElement;
+      } else {
+        element = this.createElement("title");
+        headElement._append(element);
+      }
+
+      element.textContent = value;
+    }
+  }
+
+  get dir() {
+    return this.documentElement ? this.documentElement.dir : "";
+  }
+  set dir(value) {
+    if (this.documentElement) {
+      this.documentElement.dir = value;
+    }
+  }
+
+  get head() {
+    return this.documentElement ? firstChildWithLocalName(this.documentElement, "head") : null;
+  }
+
+  get body() {
+    const { documentElement } = this;
+    if (!documentElement || documentElement._localName !== "html" ||
+        documentElement._namespaceURI !== HTML_NS) {
+      return null;
+    }
+
+    return firstChildWithLocalNames(this.documentElement, new Set(["body", "frameset"]));
+  }
+
+  set body(value) {
+    if (value === null ||
+        value._namespaceURI !== HTML_NS ||
+        (value._localName !== "body" && value._localName !== "frameset")) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot set the body to null or a non-body/frameset element",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    const bodyElement = this.body;
+    if (value === bodyElement) {
+      return;
+    }
+
+    if (bodyElement !== null) {
+      bodyElement.parentNode._replace(value, bodyElement);
+      return;
+    }
+
+    const { documentElement } = this;
+    if (documentElement === null) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot set the body when there is no document element",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    documentElement._append(value);
+  }
+
+  _runPreRemovingSteps(oldNode) {
+    // https://html.spec.whatwg.org/#focus-fixup-rule
+    if (oldNode === this.activeElement) {
+      this._lastFocusedElement = this.body;
+    }
+    for (const activeNodeIterator of this._workingNodeIterators) {
+      activeNodeIterator._preRemovingSteps(oldNode);
+    }
+  }
+
+  createEvent(type) {
+    const typeLower = type.toLowerCase();
+    const eventWrapper = eventInterfaceTable[typeLower] || null;
+
+    if (!eventWrapper) {
+      throw DOMException.create(this._globalObject, [
+        "The provided event type (\"" + type + "\") is invalid",
+        "NotSupportedError"
+      ]);
+    }
+
+    const impl = eventWrapper.createImpl(this._globalObject, [""]);
+    impl._initializedFlag = false;
+    return impl;
+  }
+
+  createRange() {
+    return Range.createImpl(this._globalObject, [], {
+      start: { node: this, offset: 0 },
+      end: { node: this, offset: 0 }
+    });
+  }
+
+  createProcessingInstruction(target, data) {
+    validateName(this._globalObject, target);
+
+    if (data.includes("?>")) {
+      throw DOMException.create(this._globalObject, [
+        "Processing instruction data cannot contain the string \"?>\"",
+        "InvalidCharacterError"
+      ]);
+    }
+
+    return ProcessingInstruction.createImpl(this._globalObject, [], {
+      ownerDocument: this,
+      target,
+      data
+    });
+  }
+
+  // https://dom.spec.whatwg.org/#dom-document-createcdatasection
+  createCDATASection(data) {
+    if (this._parsingMode === "html") {
+      throw DOMException.create(this._globalObject, [
+        "Cannot create CDATA sections in HTML documents",
+        "NotSupportedError"
+      ]);
+    }
+
+    if (data.includes("]]>")) {
+      throw DOMException.create(this._globalObject, [
+        "CDATA section data cannot contain the string \"]]>\"",
+        "InvalidCharacterError"
+      ]);
+    }
+
+    return CDATASection.createImpl(this._globalObject, [], {
+      ownerDocument: this,
+      data
+    });
+  }
+
+  createTextNode(data) {
+    return Text.createImpl(this._globalObject, [], {
+      ownerDocument: this,
+      data
+    });
+  }
+
+  createComment(data) {
+    return Comment.createImpl(this._globalObject, [], {
+      ownerDocument: this,
+      data
+    });
+  }
+
+  // https://dom.spec.whatwg.org/#dom-document-createelement
+  createElement(localName, options) {
+    validateName(this._globalObject, localName);
+
+    if (this._parsingMode === "html") {
+      localName = asciiLowercase(localName);
+    }
+
+    let isValue = null;
+    if (options && options.is !== undefined) {
+      isValue = options.is;
+    }
+
+    const namespace = this._parsingMode === "html" || this.contentType === "application/xhtml+xml" ? HTML_NS : null;
+
+    return createElement(this, localName, namespace, null, isValue, true);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-document-createelementns
+  createElementNS(namespace, qualifiedName, options) {
+    return internalCreateElementNSSteps(this, namespace, qualifiedName, options);
+  }
+
+  createDocumentFragment() {
+    return DocumentFragment.createImpl(this._globalObject, [], { ownerDocument: this });
+  }
+
+  createAttribute(localName) {
+    validateName(this._globalObject, localName);
+
+    if (this._parsingMode === "html") {
+      localName = asciiLowercase(localName);
+    }
+
+    return this._createAttribute({ localName });
+  }
+
+  createAttributeNS(namespace, name) {
+    if (namespace === undefined) {
+      namespace = null;
+    }
+    namespace = namespace !== null ? String(namespace) : namespace;
+
+    const extracted = validateAndExtract(this._globalObject, namespace, name);
+    return this._createAttribute({
+      namespace: extracted.namespace,
+      namespacePrefix: extracted.prefix,
+      localName: extracted.localName
+    });
+  }
+
+  // Using this helper function rather than directly calling generatedAttr.createImpl may be preferred in some files,
+  // to avoid introducing a potentially cyclic dependency on generated/Attr.js.
+  _createAttribute({
+    localName,
+    value,
+    namespace,
+    namespacePrefix
+  }) {
+    return generatedAttr.createImpl(this._globalObject, [], {
+      localName,
+      value,
+      namespace,
+      namespacePrefix,
+      ownerDocument: this
+    });
+  }
+
+  createTreeWalker(root, whatToShow, filter) {
+    return TreeWalker.createImpl(this._globalObject, [], { root, whatToShow, filter });
+  }
+
+  createNodeIterator(root, whatToShow, filter) {
+    const nodeIterator = NodeIterator.createImpl(this._globalObject, [], { root, whatToShow, filter });
+
+    if (hasWeakRefs) {
+      this._workingNodeIterators.add(nodeIterator);
+    } else {
+      this._workingNodeIterators.push(nodeIterator);
+      while (this._workingNodeIterators.length > 10) {
+        const toInactivate = this._workingNodeIterators.shift();
+        toInactivate._working = false;
+      }
+    }
+
+    return nodeIterator;
+  }
+
+  importNode(node, deep) {
+    if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot import a document node",
+        "NotSupportedError"
+      ]);
+    } else if (ShadowRoot.isImpl(node)) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot adopt a shadow root",
+        "NotSupportedError"
+      ]);
+    }
+
+    return clone(node, this, deep);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-document-adoptnode
+  adoptNode(node) {
+    if (node.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot adopt a document node",
+        "NotSupportedError"
+      ]);
+    } else if (ShadowRoot.isImpl(node)) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot adopt a shadow root",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    this._adoptNode(node);
+
+    return node;
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-adopt
+  _adoptNode(node) {
+    const newDocument = this;
+    const oldDocument = node._ownerDocument;
+
+    const parent = domSymbolTree.parent(node);
+    if (parent) {
+      parent._remove(node);
+    }
+
+    if (oldDocument !== newDocument) {
+      for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+        inclusiveDescendant._ownerDocument = newDocument;
+      }
+
+      for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+        if (inclusiveDescendant._ceState === "custom") {
+          enqueueCECallbackReaction(inclusiveDescendant, "adoptedCallback", [
+            idlUtils.wrapperForImpl(oldDocument),
+            idlUtils.wrapperForImpl(newDocument)
+          ]);
+        }
+      }
+
+      for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+        if (inclusiveDescendant._adoptingSteps) {
+          inclusiveDescendant._adoptingSteps(oldDocument);
+        }
+      }
+    }
+  }
+
+  get cookie() {
+    return this._cookieJar.getCookieStringSync(this.URL, { http: false });
+  }
+  set cookie(cookieStr) {
+    cookieStr = String(cookieStr);
+    this._cookieJar.setCookieSync(cookieStr, this.URL, {
+      http: false,
+      ignoreError: true
+    });
+  }
+
+  // The clear(), captureEvents(), and releaseEvents() methods must do nothing
+  clear() {}
+
+  captureEvents() {}
+
+  releaseEvents() {}
+
+  get styleSheets() {
+    if (!this._styleSheets) {
+      this._styleSheets = StyleSheetList.createImpl(this._globalObject);
+    }
+
+    // TODO: each style and link element should register its sheet on creation
+    // and remove it on removal.
+    return this._styleSheets;
+  }
+
+  get hidden() {
+    if (this._defaultView && this._defaultView._pretendToBeVisual) {
+      return false;
+    }
+
+    return true;
+  }
+
+  get visibilityState() {
+    if (this._defaultView && this._defaultView._pretendToBeVisual) {
+      return "visible";
+    }
+
+    return "prerender";
+  }
+
+  // https://w3c.github.io/selection-api/#extensions-to-document-interface
+  getSelection() {
+    return this._defaultView ? this._defaultView._selection : null;
+  }
+
+  // Needed to ensure that the resulting document has the correct prototype chain:
+  // https://dom.spec.whatwg.org/#concept-node-clone says "that implements the same interfaces as node".
+  _cloneDocument() {
+    const copy = documents.createImpl(
+      this._globalObject,
+      {
+        contentType: this.contentType,
+        encoding: this._encoding,
+        parsingMode: this._parsingMode
+      }
+    );
+
+    copy._URL = this._URL;
+    copy._origin = this._origin;
+    return copy;
+  }
+}
+
+eventAccessors.createEventAccessor(DocumentImpl.prototype, "readystatechange");
+mixin(DocumentImpl.prototype, DocumentOrShadowRootImpl.prototype);
+mixin(DocumentImpl.prototype, GlobalEventHandlersImpl.prototype);
+mixin(DocumentImpl.prototype, NonElementParentNodeImpl.prototype);
+mixin(DocumentImpl.prototype, ParentNodeImpl.prototype);
+
+DocumentImpl.prototype.getElementsByTagName = memoizeQuery(function (qualifiedName) {
+  return listOfElementsWithQualifiedName(qualifiedName, this);
+});
+
+DocumentImpl.prototype.getElementsByTagNameNS = memoizeQuery(function (namespace, localName) {
+  return listOfElementsWithNamespaceAndLocalName(namespace, localName, this);
+});
+
+DocumentImpl.prototype.getElementsByClassName = memoizeQuery(function getElementsByClassName(classNames) {
+  return listOfElementsWithClassNames(classNames, this);
+});
+
+module.exports = {
+  implementation: DocumentImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentFragment-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+"use strict";
+const { mixin } = require("../../utils");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+const NodeImpl = require("./Node-impl").implementation;
+const NonElementParentNodeImpl = require("./NonElementParentNode-impl").implementation;
+const ParentNodeImpl = require("./ParentNode-impl").implementation;
+const idlUtils = require("../generated/utils");
+
+class DocumentFragmentImpl extends NodeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, {
+      ownerDocument: idlUtils.implForWrapper(globalObject._document),
+      ...privateData
+    });
+
+    const { host } = privateData;
+    this._host = host;
+
+    this.nodeType = NODE_TYPE.DOCUMENT_FRAGMENT_NODE;
+  }
+
+  // This is implemented separately for Document (which has a _ids cache) and DocumentFragment (which does not).
+  getElementById(id) {
+    if (id === "") {
+      return null;
+    }
+
+    for (const descendant of domSymbolTree.treeIterator(this)) {
+      if (descendant.nodeType === NODE_TYPE.ELEMENT_NODE && descendant.getAttributeNS(null, "id") === id) {
+        return descendant;
+      }
+    }
+
+    return null;
+  }
+}
+
+mixin(DocumentFragmentImpl.prototype, NonElementParentNodeImpl.prototype);
+mixin(DocumentFragmentImpl.prototype, ParentNodeImpl.prototype);
+
+module.exports = {
+  implementation: DocumentFragmentImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentOrShadowRoot-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+"use strict";
+const NODE_TYPE = require("../node-type");
+const { nodeRoot } = require("../helpers/node");
+const { retarget } = require("../helpers/shadow-dom");
+
+class DocumentOrShadowRootImpl {
+  get activeElement() {
+    let candidate = this._ownerDocument._lastFocusedElement || this._ownerDocument.body;
+    if (!candidate) {
+      return null;
+    }
+    candidate = retarget(candidate, this);
+    if (nodeRoot(candidate) !== this) {
+      return null;
+    }
+    if (candidate.nodeType !== NODE_TYPE.DOCUMENT_NODE) {
+      return candidate;
+    }
+    if (candidate.body !== null) {
+      return candidate.body;
+    }
+    return candidate.documentElement;
+  }
+}
+
+module.exports = {
+  implementation: DocumentOrShadowRootImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/DocumentType-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,24 @@
+"use strict";
+const { mixin } = require("../../utils");
+const NodeImpl = require("./Node-impl").implementation;
+const ChildNodeImpl = require("./ChildNode-impl").implementation;
+
+const NODE_TYPE = require("../node-type");
+
+class DocumentTypeImpl extends NodeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this.nodeType = NODE_TYPE.DOCUMENT_TYPE_NODE;
+
+    this.name = privateData.name;
+    this.publicId = privateData.publicId;
+    this.systemId = privateData.systemId;
+  }
+}
+
+mixin(DocumentTypeImpl.prototype, ChildNodeImpl.prototype);
+
+module.exports = {
+  implementation: DocumentTypeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/Element-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,578 @@
+"use strict";
+const { addNwsapi } = require("../helpers/selectors");
+const { HTML_NS } = require("../helpers/namespaces");
+const { mixin, memoizeQuery } = require("../../utils");
+const idlUtils = require("../generated/utils");
+const NodeImpl = require("./Node-impl").implementation;
+const ParentNodeImpl = require("./ParentNode-impl").implementation;
+const ChildNodeImpl = require("./ChildNode-impl").implementation;
+const attributes = require("../attributes");
+const namedPropertiesWindow = require("../named-properties-window");
+const NODE_TYPE = require("../node-type");
+const { parseFragment } = require("../../browser/parser");
+const InnerHTMLImpl = require("../domparsing/InnerHTML-impl").implementation;
+const { fragmentSerialization } = require("../domparsing/serialization");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const DOMException = require("domexception/webidl2js-wrapper");
+const DOMTokenList = require("../generated/DOMTokenList");
+const NamedNodeMap = require("../generated/NamedNodeMap");
+const validateNames = require("../helpers/validate-names");
+const { asciiLowercase, asciiUppercase } = require("../helpers/strings");
+const { listOfElementsWithQualifiedName, listOfElementsWithNamespaceAndLocalName,
+  listOfElementsWithClassNames } = require("../node");
+const SlotableMixinImpl = require("./Slotable-impl").implementation;
+const NonDocumentTypeChildNode = require("./NonDocumentTypeChildNode-impl").implementation;
+const ShadowRoot = require("../generated/ShadowRoot");
+const Text = require("../generated/Text");
+const { isValidHostElementName } = require("../helpers/shadow-dom");
+const { isValidCustomElementName, lookupCEDefinition } = require("../helpers/custom-elements");
+
+function attachId(id, elm, doc) {
+  if (id && elm && doc) {
+    if (!doc._ids[id]) {
+      doc._ids[id] = [];
+    }
+    doc._ids[id].push(elm);
+  }
+}
+
+function detachId(id, elm, doc) {
+  if (id && elm && doc) {
+    if (doc._ids && doc._ids[id]) {
+      const elms = doc._ids[id];
+      for (let i = 0; i < elms.length; i++) {
+        if (elms[i] === elm) {
+          elms.splice(i, 1);
+          --i;
+        }
+      }
+      if (elms.length === 0) {
+        delete doc._ids[id];
+      }
+    }
+  }
+}
+
+class ElementImpl extends NodeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._initSlotableMixin();
+
+    this._namespaceURI = privateData.namespace;
+    this._prefix = privateData.prefix;
+    this._localName = privateData.localName;
+    this._ceState = privateData.ceState;
+    this._ceDefinition = privateData.ceDefinition;
+    this._isValue = privateData.isValue;
+
+    this._shadowRoot = null;
+    this._ceReactionQueue = [];
+
+    this.nodeType = NODE_TYPE.ELEMENT_NODE;
+    this.scrollTop = 0;
+    this.scrollLeft = 0;
+
+    this._attributeList = [];
+    // Used for caching.
+    this._attributesByNameMap = new Map();
+    this._attributes = NamedNodeMap.createImpl(this._globalObject, [], {
+      element: this
+    });
+
+    this._cachedTagName = null;
+  }
+
+  _attach() {
+    namedPropertiesWindow.nodeAttachedToDocument(this);
+
+    const id = this.getAttributeNS(null, "id");
+    if (id) {
+      attachId(id, this, this._ownerDocument);
+    }
+
+    super._attach();
+  }
+
+  _detach() {
+    super._detach();
+
+    namedPropertiesWindow.nodeDetachedFromDocument(this);
+
+    const id = this.getAttributeNS(null, "id");
+    if (id) {
+      detachId(id, this, this._ownerDocument);
+    }
+  }
+
+  _attrModified(name, value, oldValue) {
+    this._modified();
+    namedPropertiesWindow.elementAttributeModified(this, name, value, oldValue);
+
+    if (name === "id" && this._attached) {
+      const doc = this._ownerDocument;
+      detachId(oldValue, this, doc);
+      attachId(value, this, doc);
+    }
+
+    // update classList
+    if (name === "class" && this._classList !== undefined) {
+      this._classList.attrModified();
+    }
+
+    this._attrModifiedSlotableMixin(name, value, oldValue);
+  }
+
+  get namespaceURI() {
+    return this._namespaceURI;
+  }
+  get prefix() {
+    return this._prefix;
+  }
+  get localName() {
+    return this._localName;
+  }
+  get _qualifiedName() {
+    return this._prefix !== null ? this._prefix + ":" + this._localName : this._localName;
+  }
+  get tagName() {
+    // This getter can be a hotpath in getComputedStyle.
+    // All these are invariants during the instance lifetime so we can safely cache the computed tagName.
+    // We could create it during construction but since we already identified this as potentially slow we do it lazily.
+    if (this._cachedTagName === null) {
+      if (this.namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+        this._cachedTagName = asciiUppercase(this._qualifiedName);
+      } else {
+        this._cachedTagName = this._qualifiedName;
+      }
+    }
+    return this._cachedTagName;
+  }
+
+  get attributes() {
+    return this._attributes;
+  }
+
+  // https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml
+  get outerHTML() {
+    // TODO: maybe parse5 can give us a hook where it serializes the node itself too:
+    // https://github.com/inikulin/parse5/issues/230
+    // Alternatively, if we can create a virtual node in domSymbolTree, that'd also work.
+    // It's currently prevented by the fact that a node can't be duplicated in the same tree.
+    // Then we could get rid of all the code for childNodesForSerializing.
+    return fragmentSerialization({ childNodesForSerializing: [this], _ownerDocument: this._ownerDocument }, {
+      requireWellFormed: true,
+      globalObject: this._globalObject
+    });
+  }
+  set outerHTML(markup) {
+    let parent = domSymbolTree.parent(this);
+    const document = this._ownerDocument;
+
+    if (!parent) {
+      return;
+    }
+
+    if (parent.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+      throw DOMException.create(this._globalObject, [
+        "Modifications are not allowed for this document",
+        "NoModificationAllowedError"
+      ]);
+    }
+
+    if (parent.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+      parent = document.createElementNS(HTML_NS, "body");
+    }
+
+    const fragment = parseFragment(markup, parent);
+
+    const contextObjectParent = domSymbolTree.parent(this);
+    contextObjectParent._replace(fragment, this);
+  }
+
+  get classList() {
+    if (this._classList === undefined) {
+      this._classList = DOMTokenList.createImpl(this._globalObject, [], {
+        element: this,
+        attributeLocalName: "class"
+      });
+    }
+    return this._classList;
+  }
+
+  hasAttributes() {
+    return attributes.hasAttributes(this);
+  }
+
+  getAttributeNames() {
+    return attributes.attributeNames(this);
+  }
+
+  getAttribute(name) {
+    const attr = attributes.getAttributeByName(this, name);
+    if (!attr) {
+      return null;
+    }
+    return attr._value;
+  }
+
+  getAttributeNS(namespace, localName) {
+    const attr = attributes.getAttributeByNameNS(this, namespace, localName);
+    if (!attr) {
+      return null;
+    }
+    return attr._value;
+  }
+
+  setAttribute(name, value) {
+    validateNames.name(this._globalObject, name);
+
+    if (this._namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+      name = asciiLowercase(name);
+    }
+
+    const attribute = attributes.getAttributeByName(this, name);
+
+    if (attribute === null) {
+      const newAttr = this._ownerDocument._createAttribute({
+        localName: name,
+        value
+      });
+      attributes.appendAttribute(this, newAttr);
+      return;
+    }
+
+    attributes.changeAttribute(this, attribute, value);
+  }
+
+  setAttributeNS(namespace, name, value) {
+    const extracted = validateNames.validateAndExtract(this._globalObject, namespace, name);
+
+    // Because of widespread use of this method internally, e.g. to manually implement attribute/content reflection, we
+    // centralize the conversion to a string here, so that all call sites don't have to do it.
+    value = `${value}`;
+
+    attributes.setAttributeValue(this, extracted.localName, value, extracted.prefix, extracted.namespace);
+  }
+
+  removeAttribute(name) {
+    attributes.removeAttributeByName(this, name);
+  }
+
+  removeAttributeNS(namespace, localName) {
+    attributes.removeAttributeByNameNS(this, namespace, localName);
+  }
+
+  toggleAttribute(qualifiedName, force) {
+    validateNames.name(this._globalObject, qualifiedName);
+
+    if (this._namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+      qualifiedName = asciiLowercase(qualifiedName);
+    }
+
+    const attribute = attributes.getAttributeByName(this, qualifiedName);
+
+    if (attribute === null) {
+      if (force === undefined || force === true) {
+        const newAttr = this._ownerDocument._createAttribute({
+          localName: qualifiedName,
+          value: ""
+        });
+        attributes.appendAttribute(this, newAttr);
+        return true;
+      }
+      return false;
+    }
+
+    if (force === undefined || force === false) {
+      attributes.removeAttributeByName(this, qualifiedName);
+      return false;
+    }
+
+    return true;
+  }
+
+  hasAttribute(name) {
+    if (this._namespaceURI === HTML_NS && this._ownerDocument._parsingMode === "html") {
+      name = asciiLowercase(name);
+    }
+
+    return attributes.hasAttributeByName(this, name);
+  }
+
+  hasAttributeNS(namespace, localName) {
+    if (namespace === "") {
+      namespace = null;
+    }
+
+    return attributes.hasAttributeByNameNS(this, namespace, localName);
+  }
+
+  getAttributeNode(name) {
+    return attributes.getAttributeByName(this, name);
+  }
+
+  getAttributeNodeNS(namespace, localName) {
+    return attributes.getAttributeByNameNS(this, namespace, localName);
+  }
+
+  setAttributeNode(attr) {
+    // eslint-disable-next-line no-restricted-properties
+    return attributes.setAttribute(this, attr);
+  }
+
+  setAttributeNodeNS(attr) {
+    // eslint-disable-next-line no-restricted-properties
+    return attributes.setAttribute(this, attr);
+  }
+
+  removeAttributeNode(attr) {
+    // eslint-disable-next-line no-restricted-properties
+    if (!attributes.hasAttribute(this, attr)) {
+      throw DOMException.create(this._globalObject, [
+        "Tried to remove an attribute that was not present",
+        "NotFoundError"
+      ]);
+    }
+
+    // eslint-disable-next-line no-restricted-properties
+    attributes.removeAttribute(this, attr);
+
+    return attr;
+  }
+
+  getBoundingClientRect() {
+    return {
+      x: 0,
+      y: 0,
+      bottom: 0,
+      height: 0,
+      left: 0,
+      right: 0,
+      top: 0,
+      width: 0
+    };
+  }
+
+  getClientRects() {
+    return [];
+  }
+
+  get scrollWidth() {
+    return 0;
+  }
+
+  get scrollHeight() {
+    return 0;
+  }
+
+  get clientTop() {
+    return 0;
+  }
+
+  get clientLeft() {
+    return 0;
+  }
+
+  get clientWidth() {
+    return 0;
+  }
+
+  get clientHeight() {
+    return 0;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-element-attachshadow
+  attachShadow(init) {
+    const { _ownerDocument, _namespaceURI, _localName, _isValue } = this;
+
+    if (this.namespaceURI !== HTML_NS) {
+      throw DOMException.create(this._globalObject, [
+        "This element does not support attachShadow. This element is not part of the HTML namespace.",
+        "NotSupportedError"
+      ]);
+    }
+
+    if (!isValidHostElementName(_localName) && !isValidCustomElementName(_localName)) {
+      const message = "This element does not support attachShadow. This element is not a custom element nor " +
+        "a standard element supporting a shadow root.";
+      throw DOMException.create(this._globalObject, [message, "NotSupportedError"]);
+    }
+
+    if (isValidCustomElementName(_localName) || _isValue) {
+      const definition = lookupCEDefinition(_ownerDocument, _namespaceURI, _localName, _isValue);
+
+      if (definition && definition.disableShadow) {
+        throw DOMException.create(this._globalObject, [
+          "Shadow root cannot be create on a custom element with disabled shadow",
+          "NotSupportedError"
+        ]);
+      }
+    }
+
+    if (this._shadowRoot !== null) {
+      throw DOMException.create(this._globalObject, [
+        "Shadow root cannot be created on a host which already hosts a shadow tree.",
+        "NotSupportedError"
+      ]);
+    }
+
+    const shadow = ShadowRoot.createImpl(this._globalObject, [], {
+      ownerDocument: this.ownerDocument,
+      mode: init.mode,
+      host: this
+    });
+
+    this._shadowRoot = shadow;
+
+    return shadow;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-element-shadowroot
+  get shadowRoot() {
+    const shadow = this._shadowRoot;
+
+    if (shadow === null || shadow.mode === "closed") {
+      return null;
+    }
+
+    return shadow;
+  }
+
+  // https://dom.spec.whatwg.org/#insert-adjacent
+  _insertAdjacent(element, where, node) {
+    where = asciiLowercase(where);
+
+    if (where === "beforebegin") {
+      if (element.parentNode === null) {
+        return null;
+      }
+      return element.parentNode._preInsert(node, element);
+    }
+    if (where === "afterbegin") {
+      return element._preInsert(node, element.firstChild);
+    }
+    if (where === "beforeend") {
+      return element._preInsert(node, null);
+    }
+    if (where === "afterend") {
+      if (element.parentNode === null) {
+        return null;
+      }
+      return element.parentNode._preInsert(node, element.nextSibling);
+    }
+
+    throw DOMException.create(this._globalObject, [
+      'Must provide one of "beforebegin", "afterbegin", "beforeend", or "afterend".',
+      "SyntaxError"
+    ]);
+  }
+
+  insertAdjacentElement(where, element) {
+    return this._insertAdjacent(this, where, element);
+  }
+
+  insertAdjacentText(where, data) {
+    const text = Text.createImpl(this._globalObject, [], { data, ownerDocument: this._ownerDocument });
+
+    this._insertAdjacent(this, where, text);
+  }
+
+  // https://w3c.github.io/DOM-Parsing/#dom-element-insertadjacenthtml
+  insertAdjacentHTML(position, text) {
+    position = asciiLowercase(position);
+
+    let context;
+    switch (position) {
+      case "beforebegin":
+      case "afterend": {
+        context = this.parentNode;
+        if (context === null || context.nodeType === NODE_TYPE.DOCUMENT_NODE) {
+          throw DOMException.create(this._globalObject, [
+            "Cannot insert HTML adjacent to parent-less nodes or children of document nodes.",
+            "NoModificationAllowedError"
+          ]);
+        }
+        break;
+      }
+      case "afterbegin":
+      case "beforeend": {
+        context = this;
+        break;
+      }
+      default: {
+        throw DOMException.create(this._globalObject, [
+          'Must provide one of "beforebegin", "afterbegin", "beforeend", or "afterend".',
+          "SyntaxError"
+        ]);
+      }
+    }
+
+    if (
+      context.nodeType !== NODE_TYPE.ELEMENT_NODE ||
+      (
+        context._ownerDocument._parsingMode === "html" &&
+        context._localName === "html" &&
+        context._namespaceURI === HTML_NS
+      )
+    ) {
+      context = context._ownerDocument.createElement("body");
+    }
+
+    const fragment = parseFragment(text, context);
+
+    switch (position) {
+      case "beforebegin": {
+        this.parentNode._insert(fragment, this);
+        break;
+      }
+      case "afterbegin": {
+        this._insert(fragment, this.firstChild);
+        break;
+      }
+      case "beforeend": {
+        this._append(fragment);
+        break;
+      }
+      case "afterend": {
+        this.parentNode._insert(fragment, this.nextSibling);
+        break;
+      }
+    }
+  }
+
+  closest(selectors) {
+    const matcher = addNwsapi(this);
+    return matcher.closest(selectors, idlUtils.wrapperForImpl(this));
+  }
+}
+
+mixin(ElementImpl.prototype, NonDocumentTypeChildNode.prototype);
+mixin(ElementImpl.prototype, ParentNodeImpl.prototype);
+mixin(ElementImpl.prototype, ChildNodeImpl.prototype);
+mixin(ElementImpl.prototype, SlotableMixinImpl.prototype);
+mixin(ElementImpl.prototype, InnerHTMLImpl.prototype);
+
+ElementImpl.prototype.getElementsByTagName = memoizeQuery(function (qualifiedName) {
+  return listOfElementsWithQualifiedName(qualifiedName, this);
+});
+
+ElementImpl.prototype.getElementsByTagNameNS = memoizeQuery(function (namespace, localName) {
+  return listOfElementsWithNamespaceAndLocalName(namespace, localName, this);
+});
+
+ElementImpl.prototype.getElementsByClassName = memoizeQuery(function (classNames) {
+  return listOfElementsWithClassNames(classNames, this);
+});
+
+ElementImpl.prototype.matches = function (selectors) {
+  const matcher = addNwsapi(this);
+
+  return matcher.match(selectors, idlUtils.wrapperForImpl(this));
+};
+
+ElementImpl.prototype.webkitMatchesSelector = ElementImpl.prototype.matches;
+
+module.exports = {
+  implementation: ElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/ElementCSSInlineStyle-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,25 @@
+"use strict";
+const cssstyle = require("cssstyle");
+
+class ElementCSSInlineStyle {
+  _initElementCSSInlineStyle() {
+    this._settingCssText = false;
+    this._style = new cssstyle.CSSStyleDeclaration(newCssText => {
+      if (!this._settingCssText) {
+        this._settingCssText = true;
+        this.setAttributeNS(null, "style", newCssText);
+        this._settingCssText = false;
+      }
+    });
+  }
+  get style() {
+    return this._style;
+  }
+  set style(value) {
+    this._style.cssText = value;
+  }
+}
+
+module.exports = {
+  implementation: ElementCSSInlineStyle
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/ElementContentEditable-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,7 @@
+"use strict";
+
+class ElementContentEditableImpl { }
+
+module.exports = {
+  implementation: ElementContentEditableImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/GlobalEventHandlers-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,95 @@
+"use strict";
+
+const { appendHandler, createEventAccessor } = require("../helpers/create-event-accessor");
+
+const events = new Set([
+  "abort", "autocomplete",
+  "autocompleteerror", "blur",
+  "cancel", "canplay", "canplaythrough",
+  "change", "click",
+  "close", "contextmenu",
+  "cuechange", "dblclick",
+  "drag", "dragend",
+  "dragenter",
+  "dragleave", "dragover",
+  "dragstart", "drop",
+  "durationchange", "emptied",
+  "ended", "error", "focus",
+  "input", "invalid",
+  "keydown", "keypress",
+  "keyup", "load", "loadeddata",
+  "loadedmetadata", "loadstart",
+  "mousedown", "mouseenter",
+  "mouseleave", "mousemove",
+  "mouseout", "mouseover",
+  "mouseup", "wheel",
+  "pause", "play",
+  "playing", "progress",
+  "ratechange", "reset",
+  "resize", "scroll",
+  "securitypolicyviolation",
+  "seeked", "seeking",
+  "select", "sort", "stalled",
+  "submit", "suspend",
+  "timeupdate", "toggle",
+  "volumechange", "waiting"
+]);
+
+class GlobalEventHandlersImpl {
+  _initGlobalEvents() {
+    this._registeredHandlers = new Set();
+    this._eventHandlers = Object.create(null);
+  }
+
+  _getEventHandlerTarget() {
+    return this;
+  }
+
+  _getEventHandlerFor(event) {
+    const target = this._getEventHandlerTarget(event);
+    if (!target) {
+      return null;
+    }
+
+    return target._eventHandlers[event];
+  }
+
+  _setEventHandlerFor(event, handler) {
+    const target = this._getEventHandlerTarget(event);
+    if (!target) {
+      return;
+    }
+
+    if (!target._registeredHandlers.has(event) && handler !== null) {
+      target._registeredHandlers.add(event);
+      appendHandler(target, event);
+    }
+    target._eventHandlers[event] = handler;
+  }
+
+  _globalEventChanged(event) {
+    const propName = "on" + event;
+    if (!(propName in this)) {
+      return;
+    }
+
+    // Only translate attribute changes into properties when runScripts: "dangerously" is set.
+    // Documents without a browsing context (i.e. without a _defaultView) never run scripts.
+    const runScripts = "_runScripts" in this ? this._runScripts : (this._ownerDocument._defaultView || {})._runScripts;
+    if (runScripts !== "dangerously") {
+      return;
+    }
+
+    const val = this.getAttributeNS(null, propName);
+    const handler = val === null ? null : { body: val };
+    this._setEventHandlerFor(event, handler);
+  }
+}
+
+for (const event of events) {
+  createEventAccessor(GlobalEventHandlersImpl.prototype, event);
+}
+
+module.exports = {
+  implementation: GlobalEventHandlersImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAnchorElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,50 @@
+"use strict";
+const { mixin } = require("../../utils");
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const HTMLHyperlinkElementUtilsImpl = require("./HTMLHyperlinkElementUtils-impl").implementation;
+
+class HTMLAnchorElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._htmlHyperlinkElementUtilsSetup();
+
+    this._hasActivationBehavior = true;
+  }
+
+  _activationBehavior() {
+    this._followAHyperlink();
+  }
+
+  get relList() {
+    if (this._relList === undefined) {
+      this._relList = DOMTokenList.createImpl(this._globalObject, [], {
+        element: this,
+        attributeLocalName: "rel"
+      });
+    }
+    return this._relList;
+  }
+
+  get text() {
+    return this.textContent;
+  }
+  set text(v) {
+    this.textContent = v;
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    if (name === "rel" && this._relList !== undefined) {
+      this._relList.attrModified();
+    }
+  }
+}
+
+mixin(HTMLAnchorElementImpl.prototype, HTMLHyperlinkElementUtilsImpl.prototype);
+
+module.exports = {
+  implementation: HTMLAnchorElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAreaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+"use strict";
+const { mixin } = require("../../utils");
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const HTMLHyperlinkElementUtilsImpl = require("./HTMLHyperlinkElementUtils-impl").implementation;
+
+class HTMLAreaElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._htmlHyperlinkElementUtilsSetup();
+
+    this._hasActivationBehavior = true;
+  }
+
+  _activationBehavior() {
+    this._followAHyperlink();
+  }
+
+  get relList() {
+    if (this._relList === undefined) {
+      this._relList = DOMTokenList.createImpl(this._globalObject, [], {
+        element: this,
+        attributeLocalName: "rel"
+      });
+    }
+    return this._relList;
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    if (name === "rel" && this._relList !== undefined) {
+      this._relList.attrModified();
+    }
+  }
+}
+
+mixin(HTMLAreaElementImpl.prototype, HTMLHyperlinkElementUtilsImpl.prototype);
+
+module.exports = {
+  implementation: HTMLAreaElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLAudioElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLMediaElementImpl = require("./HTMLMediaElement-impl").implementation;
+
+class HTMLAudioElementImpl extends HTMLMediaElementImpl { }
+
+module.exports = {
+  implementation: HTMLAudioElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBRElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLBRElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLBRElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBaseElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,27 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { fallbackBaseURL } = require("../helpers/document-base-url");
+
+class HTMLBaseElementImpl extends HTMLElementImpl {
+  get href() {
+    const document = this._ownerDocument;
+
+    const url = this.hasAttributeNS(null, "href") ? this.getAttributeNS(null, "href") : "";
+    const parsed = whatwgURL.parseURL(url, { baseURL: fallbackBaseURL(document) });
+
+    if (parsed === null) {
+      return url;
+    }
+
+    return whatwgURL.serializeURL(parsed);
+  }
+
+  set href(value) {
+    this.setAttributeNS(null, "href", value);
+  }
+}
+
+module.exports = {
+  implementation: HTMLBaseElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLBodyElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+const { mixin } = require("../../utils");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const WindowEventHandlersImpl = require("./WindowEventHandlers-impl").implementation;
+
+class HTMLBodyElementImpl extends HTMLElementImpl {
+  constructor(...args) {
+    super(...args);
+    this._proxyWindowEventsToWindow();
+  }
+}
+
+mixin(HTMLBodyElementImpl.prototype, WindowEventHandlersImpl.prototype);
+
+module.exports = {
+  implementation: HTMLBodyElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLButtonElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,79 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const { isDisabled, formOwner, getLabelsForLabelable } = require("../helpers/form-controls");
+const { asciiLowercase } = require("../helpers/strings");
+
+class HTMLButtonElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._customValidityErrorMessage = "";
+    this._labels = null;
+
+    this._hasActivationBehavior = true;
+  }
+
+  _activationBehavior() {
+    const { form } = this;
+    if (form && !isDisabled(this)) {
+      if (this.type === "submit") {
+        form._doSubmit();
+      }
+      if (this.type === "reset") {
+        form._doReset();
+      }
+    }
+  }
+
+  _getValue() {
+    const valueAttr = this.getAttributeNS(null, "value");
+    return valueAttr === null ? "" : valueAttr;
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get type() {
+    const typeAttr = asciiLowercase(this.getAttributeNS(null, "type") || "");
+    switch (typeAttr) {
+      case "submit":
+      case "reset":
+      case "button":
+        return typeAttr;
+      default:
+        return "submit";
+    }
+  }
+
+  set type(v) {
+    v = asciiLowercase(String(v));
+    switch (v) {
+      case "submit":
+      case "reset":
+      case "button":
+        this.setAttributeNS(null, "type", v);
+        break;
+      default:
+        this.setAttributeNS(null, "type", "submit");
+        break;
+    }
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    return this.type === "reset" || this.type === "button";
+  }
+}
+
+mixin(HTMLButtonElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLButtonElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCanvasElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,130 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const notImplemented = require("../../browser/not-implemented");
+const idlUtils = require("../generated/utils");
+const { Canvas } = require("../../utils");
+
+class HTMLCanvasElementImpl extends HTMLElementImpl {
+  _attrModified(name, value, oldValue) {
+    if (this._canvas && (name === "width" || name === "height")) {
+      this._canvas[name] = parseInt(value);
+    }
+
+    super._attrModified(name, value, oldValue);
+  }
+
+  _getCanvas() {
+    if (Canvas && !this._canvas) {
+      this._canvas = Canvas.createCanvas(this.width, this.height);
+    }
+    return this._canvas;
+  }
+
+  getContext(contextId) {
+    const canvas = this._getCanvas();
+    if (canvas) {
+      if (!this._context) {
+        this._context = canvas.getContext(contextId) || null;
+        if (this._context) {
+          // Override the native canvas reference with our wrapper. This is the
+          // reason why we need to locally cache _context, since each call to
+          // canvas.getContext(contextId) would replace this reference again.
+          // Perhaps in the longer term, a better solution would be to create a
+          // full wrapper for the Context object as well.
+          this._context.canvas = idlUtils.wrapperForImpl(this);
+          wrapNodeCanvasMethod(this._context, "createPattern");
+          wrapNodeCanvasMethod(this._context, "drawImage");
+        }
+      }
+      return this._context;
+    }
+
+    notImplemented(
+      "HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)",
+      this._ownerDocument._defaultView
+    );
+    return null;
+  }
+
+  toDataURL(...args) {
+    const canvas = this._getCanvas();
+    if (canvas) {
+      return canvas.toDataURL(...args);
+    }
+
+    notImplemented(
+      "HTMLCanvasElement.prototype.toDataURL (without installing the canvas npm package)",
+      this._ownerDocument._defaultView
+    );
+    return null;
+  }
+
+  toBlob(callback, type, qualityArgument) {
+    const window = this._ownerDocument._defaultView;
+    const canvas = this._getCanvas();
+    if (canvas) {
+      const options = {};
+      switch (type) {
+        case "image/jpg":
+        case "image/jpeg":
+          type = "image/jpeg";
+          options.quality = qualityArgument;
+          break;
+        default:
+          type = "image/png";
+      }
+      canvas.toBuffer((err, buff) => {
+        if (err) {
+          throw err;
+        }
+        callback(new window.Blob([buff], { type }));
+      }, type, options);
+    } else {
+      notImplemented(
+        "HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)",
+        window
+      );
+    }
+  }
+
+  get width() {
+    const parsed = parseInt(this.getAttributeNS(null, "width"));
+    return isNaN(parsed) || parsed < 0 || parsed > 2147483647 ? 300 : parsed;
+  }
+
+  set width(v) {
+    v = v > 2147483647 ? 300 : v;
+    this.setAttributeNS(null, "width", String(v));
+  }
+
+  get height() {
+    const parsed = parseInt(this.getAttributeNS(null, "height"));
+    return isNaN(parsed) || parsed < 0 || parsed > 2147483647 ? 150 : parsed;
+  }
+
+  set height(v) {
+    v = v > 2147483647 ? 150 : v;
+    this.setAttributeNS(null, "height", String(v));
+  }
+}
+
+// We need to wrap the methods that receive an image or canvas object
+// (luckily, always as the first argument), so that these objects can be
+// unwrapped an the expected types passed.
+function wrapNodeCanvasMethod(ctx, name) {
+  const prev = ctx[name];
+  ctx[name] = function (image, ...rest) {
+    const impl = idlUtils.implForWrapper(image);
+    if (impl) {
+      if (impl instanceof HTMLCanvasElementImpl && !impl._canvas) {
+        impl._getCanvas();
+      }
+      image = impl._image || impl._canvas;
+    }
+    return prev.call(ctx, image, ...rest);
+  };
+}
+
+module.exports = {
+  implementation: HTMLCanvasElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLCollection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,96 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+const { HTML_NS } = require("../helpers/namespaces");
+
+exports.implementation = class HTMLCollectionImpl {
+  constructor(globalObject, args, privateData) {
+    this._list = [];
+    this._version = -1;
+    this._element = privateData.element;
+    this._query = privateData.query;
+
+    this._globalObject = globalObject;
+
+    this._update();
+  }
+  get length() {
+    this._update();
+    return this._list.length;
+  }
+  item(index) {
+    this._update();
+    return this._list[index] || null;
+  }
+  namedItem(key) {
+    if (key === "") {
+      return null;
+    }
+    this._update();
+    for (const element of this._list) {
+      if (element.getAttributeNS(null, "id") === key) {
+        return element;
+      }
+      if (element._namespaceURI === HTML_NS) {
+        const name = element.getAttributeNS(null, "name");
+        if (name === key) {
+          return element;
+        }
+      }
+    }
+    return null;
+  }
+  _update() {
+    if (this._version < this._element._version) {
+      const snapshot = this._query();
+      for (let i = 0; i < snapshot.length; i++) {
+        this._list[i] = snapshot[i];
+      }
+      this._list.length = snapshot.length;
+      this._version = this._element._version;
+    }
+  }
+  get [idlUtils.supportedPropertyIndices]() {
+    this._update();
+    return this._list.keys();
+  }
+  get [idlUtils.supportedPropertyNames]() {
+    this._update();
+    const result = new Set();
+    for (const element of this._list) {
+      const id = element.getAttributeNS(null, "id");
+      if (id) {
+        result.add(id);
+      }
+      if (element._namespaceURI === HTML_NS) {
+        const name = element.getAttributeNS(null, "name");
+        if (name) {
+          result.add(name);
+        }
+      }
+    }
+    return result;
+  }
+
+  // Inherit some useful functions from Array.
+  [Symbol.iterator]() {
+    this._update();
+    return this._list[Symbol.iterator]();
+  }
+  entries() {
+    this._update();
+    return this._list.entries();
+  }
+  filter(...args) {
+    this._update();
+    return this._list.filter(...args);
+  }
+  map(...args) {
+    this._update();
+    return this._list.map(...args);
+  }
+  indexOf(...args) {
+    this._update();
+    return this._list.indexOf(...args);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDListElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLDListElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDataElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLDataElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDataListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+"use strict";
+
+const HTMLCollection = require("../generated/HTMLCollection");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const { descendantsByLocalName } = require("../helpers/traversal");
+
+class HTMLDataListElementImpl extends HTMLElementImpl {
+  // https://html.spec.whatwg.org/multipage/form-elements.html#dom-datalist-options
+  get options() {
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => descendantsByLocalName(this, "option")
+    });
+  }
+}
+
+module.exports = {
+  implementation: HTMLDataListElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDetailsElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,35 @@
+"use strict";
+
+const { fireAnEvent } = require("../helpers/events");
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDetailsElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._taskQueue = null;
+  }
+
+  _dispatchToggleEvent() {
+    this._taskQueue = null;
+
+    fireAnEvent("toggle", this);
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    if (name === "open" && this._taskQueue === null) {
+      // Check that the attribute is added or removed, not merely changed
+      if ((value !== oldValue && value !== null && oldValue === null) ||
+          (value === null && oldValue !== null)) {
+        this._taskQueue = setTimeout(this._dispatchToggleEvent.bind(this), 0);
+      }
+    }
+  }
+}
+
+module.exports = {
+  implementation: HTMLDetailsElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDialogElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDialogElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLDialogElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDirectoryElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDirectoryElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLDirectoryElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLDivElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLDivElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLDivElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,160 @@
+"use strict";
+const { mixin } = require("../../utils");
+const ElementImpl = require("./Element-impl").implementation;
+const MouseEvent = require("../generated/MouseEvent");
+const ElementCSSInlineStyleImpl = require("./ElementCSSInlineStyle-impl").implementation;
+const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
+const HTMLOrSVGElementImpl = require("./HTMLOrSVGElement-impl").implementation;
+const { firstChildWithLocalName } = require("../helpers/traversal");
+const { isDisabled } = require("../helpers/form-controls");
+const { fireAnEvent } = require("../helpers/events");
+const { asciiLowercase } = require("../helpers/strings");
+
+class HTMLElementImpl extends ElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._initHTMLOrSVGElement();
+    this._initElementCSSInlineStyle();
+    this._initGlobalEvents();
+
+    this._clickInProgress = false;
+
+    // <summary> uses HTMLElement and has activation behavior
+    this._hasActivationBehavior = this._localName === "summary";
+  }
+
+  _activationBehavior() {
+    const parent = this.parentNode;
+    if (parent && parent._localName === "details" &&
+        this === firstChildWithLocalName(parent, "summary")) {
+      if (parent.hasAttributeNS(null, "open")) {
+        parent.removeAttributeNS(null, "open");
+      } else {
+        parent.setAttributeNS(null, "open", "");
+      }
+    }
+  }
+
+  // https://html.spec.whatwg.org/multipage/dom.html#the-translate-attribute
+  get translate() {
+    const translateAttr = this.getAttributeNS(null, "translate");
+    const translateAttrString = asciiLowercase(translateAttr || "");
+
+    if (translateAttrString === "yes" || (translateAttr && translateAttrString === "")) {
+      return true;
+    } else if (translateAttrString === "no") {
+      return false;
+    }
+
+    if (this === this.ownerDocument.documentElement) {
+      return true;
+    }
+
+    return this.parentElement && this.parentElement.translate;
+  }
+  set translate(value) {
+    if (value === true) {
+      this.setAttributeNS(null, "translate", "yes");
+    } else {
+      this.setAttributeNS(null, "translate", "no");
+    }
+  }
+
+  click() {
+    // https://html.spec.whatwg.org/multipage/interaction.html#dom-click
+    // https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-synthetic-mouse-event
+
+    if (isDisabled(this)) {
+      return;
+    }
+
+    if (this._clickInProgress) {
+      return;
+    }
+
+    this._clickInProgress = true;
+
+    // https://github.com/whatwg/html/issues/4451
+    // https://github.com/whatwg/html/issues/4452
+    fireAnEvent("click", this, MouseEvent, {
+      bubbles: true,
+      cancelable: true,
+      composed: true,
+      isTrusted: false,
+      view: this.ownerDocument.defaultView
+    });
+
+    this._clickInProgress = false;
+  }
+
+  get draggable() {
+    const attributeValue = asciiLowercase(this.getAttributeNS(null, "draggable") || "");
+
+    if (attributeValue === "true") {
+      return true;
+    } else if (attributeValue === "false") {
+      return false;
+    }
+
+    return this._localName === "img" || (this._localName === "a" && this.hasAttributeNS(null, "href"));
+  }
+  set draggable(value) {
+    this.setAttributeNS(null, "draggable", String(value));
+  }
+
+  get dir() {
+    let dirValue = this.getAttributeNS(null, "dir");
+    if (dirValue !== null) {
+      dirValue = dirValue.toLowerCase();
+
+      if (["ltr", "rtl", "auto"].includes(dirValue)) {
+        return dirValue;
+      }
+    }
+    return "";
+  }
+  set dir(value) {
+    this.setAttributeNS(null, "dir", value);
+  }
+
+  // Keep in sync with SVGElement. https://github.com/jsdom/jsdom/issues/2599
+  _attrModified(name, value, oldValue) {
+    if (name === "style" && value !== oldValue && !this._settingCssText) {
+      this._settingCssText = true;
+      this._style.cssText = value;
+      this._settingCssText = false;
+    } else if (name.startsWith("on")) {
+      this._globalEventChanged(name.substring(2));
+    }
+
+    super._attrModified(name, value, oldValue);
+  }
+
+  get offsetParent() {
+    return null;
+  }
+
+  get offsetTop() {
+    return 0;
+  }
+
+  get offsetLeft() {
+    return 0;
+  }
+
+  get offsetWidth() {
+    return 0;
+  }
+
+  get offsetHeight() {
+    return 0;
+  }
+}
+
+mixin(HTMLElementImpl.prototype, ElementCSSInlineStyleImpl.prototype);
+mixin(HTMLElementImpl.prototype, GlobalEventHandlersImpl.prototype);
+mixin(HTMLElementImpl.prototype, HTMLOrSVGElementImpl.prototype);
+
+module.exports = {
+  implementation: HTMLElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLEmbedElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLEmbedElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+  implementation: HTMLEmbedElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFieldSetElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+"use strict";
+const HTMLCollection = require("../generated/HTMLCollection");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { formOwner } = require("../helpers/form-controls");
+const { mixin } = require("../../utils");
+const { descendantsByLocalNames } = require("../helpers/traversal");
+
+const listedElements = new Set(["button", "fieldset", "input", "object", "output", "select", "textarea"]);
+
+class HTMLFieldSetElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._customValidityErrorMessage = "";
+  }
+
+  get elements() {
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => descendantsByLocalNames(this, listedElements)
+    });
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get type() {
+    return "fieldset";
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    return true;
+  }
+}
+
+mixin(HTMLFieldSetElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLFieldSetElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFontElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLFontElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLFontElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,226 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { serializeURL } = require("whatwg-url");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { fireAnEvent } = require("../helpers/events");
+const { formOwner, isListed, isSubmittable, isSubmitButton } = require("../helpers/form-controls");
+const HTMLCollection = require("../generated/HTMLCollection");
+const notImplemented = require("../../browser/not-implemented");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+
+const encTypes = new Set([
+  "application/x-www-form-urlencoded",
+  "multipart/form-data",
+  "text/plain"
+]);
+
+const methods = new Set([
+  "get",
+  "post",
+  "dialog"
+]);
+
+const constraintValidationPositiveResult = Symbol("positive");
+const constraintValidationNegativeResult = Symbol("negative");
+
+class HTMLFormElementImpl extends HTMLElementImpl {
+  _descendantAdded(parent, child) {
+    const form = this;
+    for (const el of domSymbolTree.treeIterator(child)) {
+      if (typeof el._changedFormOwner === "function") {
+        el._changedFormOwner(form);
+      }
+    }
+
+    super._descendantAdded(parent, child);
+  }
+
+  _descendantRemoved(parent, child) {
+    for (const el of domSymbolTree.treeIterator(child)) {
+      if (typeof el._changedFormOwner === "function") {
+        el._changedFormOwner(null);
+      }
+    }
+
+    super._descendantRemoved(parent, child);
+  }
+
+  _getElementNodes() {
+    return domSymbolTree.treeToArray(this.getRootNode({}), {
+      filter: node => {
+        if (!isListed(node) || (node._localName === "input" && node.type === "image")) {
+          return false;
+        }
+
+        return formOwner(node) === this;
+      }
+    });
+  }
+
+  // https://html.spec.whatwg.org/multipage/forms.html#dom-form-elements
+  get elements() {
+    // TODO: Return a HTMLFormControlsCollection
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this.getRootNode({}),
+      query: () => this._getElementNodes()
+    });
+  }
+
+  get length() {
+    return this.elements.length;
+  }
+
+  _doSubmit() {
+    if (!this.isConnected) {
+      return;
+    }
+
+    this.submit();
+  }
+
+  submit() {
+    if (!fireAnEvent("submit", this, undefined, { bubbles: true, cancelable: true })) {
+      return;
+    }
+
+    notImplemented("HTMLFormElement.prototype.submit", this._ownerDocument._defaultView);
+  }
+
+  requestSubmit(submitter = undefined) {
+    if (submitter !== undefined) {
+      if (!isSubmitButton(submitter)) {
+        throw new TypeError("The specified element is not a submit button");
+      }
+      if (submitter.form !== this) {
+        throw DOMException.create(this._globalObject, [
+          "The specified element is not owned by this form element",
+          "NotFoundError"
+        ]);
+      }
+    }
+
+    if (!fireAnEvent("submit", this, undefined, { bubbles: true, cancelable: true })) {
+      return;
+    }
+
+    notImplemented("HTMLFormElement.prototype.requestSubmit", this._ownerDocument._defaultView);
+  }
+
+  _doReset() {
+    if (!this.isConnected) {
+      return;
+    }
+
+    this.reset();
+  }
+
+  reset() {
+    if (!fireAnEvent("reset", this, undefined, { bubbles: true, cancelable: true })) {
+      return;
+    }
+
+    for (const el of this.elements) {
+      if (typeof el._formReset === "function") {
+        el._formReset();
+      }
+    }
+  }
+
+  get method() {
+    let method = this.getAttributeNS(null, "method");
+    if (method) {
+      method = method.toLowerCase();
+    }
+
+    if (methods.has(method)) {
+      return method;
+    }
+    return "get";
+  }
+
+  set method(V) {
+    this.setAttributeNS(null, "method", V);
+  }
+
+  get enctype() {
+    let type = this.getAttributeNS(null, "enctype");
+    if (type) {
+      type = type.toLowerCase();
+    }
+
+    if (encTypes.has(type)) {
+      return type;
+    }
+    return "application/x-www-form-urlencoded";
+  }
+
+  set enctype(V) {
+    this.setAttributeNS(null, "enctype", V);
+  }
+
+  get action() {
+    const attributeValue = this.getAttributeNS(null, "action");
+    if (attributeValue === null || attributeValue === "") {
+      return this._ownerDocument.URL;
+    }
+    const urlRecord = parseURLToResultingURLRecord(attributeValue, this._ownerDocument);
+    if (urlRecord === null) {
+      return attributeValue;
+    }
+    return serializeURL(urlRecord);
+  }
+
+  set action(V) {
+    this.setAttributeNS(null, "action", V);
+  }
+
+  // If the checkValidity() method is invoked, the user agent must statically validate the
+  // constraints of the form element, and return true if the constraint validation returned
+  // a positive result, and false if it returned a negative result.
+  checkValidity() {
+    return this._staticallyValidateConstraints().result === constraintValidationPositiveResult;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#interactively-validate-the-constraints
+  reportValidity() {
+    return this.checkValidity();
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#statically-validate-the-constraints
+  _staticallyValidateConstraints() {
+    const controls = [];
+    for (const el of this.elements) {
+      if (el.form === this && isSubmittable(el)) {
+        controls.push(el);
+      }
+    }
+
+    const invalidControls = [];
+
+    for (const control of controls) {
+      if (control._isCandidateForConstraintValidation() && !control._satisfiesConstraints()) {
+        invalidControls.push(control);
+      }
+    }
+
+    if (invalidControls.length === 0) {
+      return { result: constraintValidationPositiveResult };
+    }
+
+    const unhandledInvalidControls = [];
+    for (const invalidControl of invalidControls) {
+      const notCancelled = fireAnEvent("invalid", invalidControl, undefined, { cancelable: true });
+      if (notCancelled) {
+        unhandledInvalidControls.push(invalidControl);
+      }
+    }
+
+    return { result: constraintValidationNegativeResult, unhandledInvalidControls };
+  }
+}
+
+module.exports = {
+  implementation: HTMLFormElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,261 @@
+"use strict";
+
+const MIMEType = require("whatwg-mimetype");
+const whatwgEncoding = require("whatwg-encoding");
+const { parseURL, serializeURL } = require("whatwg-url");
+const sniffHTMLEncoding = require("html-encoding-sniffer");
+
+const window = require("../../browser/Window");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { evaluateJavaScriptURL } = require("../window/navigation");
+const { parseIntoDocument } = require("../../browser/parser");
+const { documentBaseURL } = require("../helpers/document-base-url");
+const { fireAnEvent } = require("../helpers/events");
+const { getAttributeValue } = require("../attributes");
+const idlUtils = require("../generated/utils");
+
+function fireLoadEvent(document, frame, attaching) {
+  if (attaching) {
+    fireAnEvent("load", frame);
+
+    return;
+  }
+
+  const dummyPromise = Promise.resolve();
+
+  function onLoad() {
+    fireAnEvent("load", frame);
+  }
+
+  document._queue.push(dummyPromise, onLoad);
+}
+
+function fetchFrame(serializedURL, frame, document, contentDoc) {
+  const resourceLoader = document._resourceLoader;
+
+  let request;
+
+  function onFrameLoaded(data) {
+    const sniffOptions = {
+      defaultEncoding: document._encoding
+    };
+
+    if (request.response) {
+      const contentType = MIMEType.parse(request.response.headers["content-type"]) || new MIMEType("text/plain");
+      sniffOptions.transportLayerEncodingLabel = contentType.parameters.get("charset");
+
+      if (contentType) {
+        if (contentType.isXML()) {
+          contentDoc._parsingMode = "xml";
+        }
+        contentDoc.contentType = contentType.essence;
+      }
+    }
+
+    const encoding = sniffHTMLEncoding(data, sniffOptions);
+    contentDoc._encoding = encoding;
+
+    const html = whatwgEncoding.decode(data, contentDoc._encoding);
+
+    try {
+      parseIntoDocument(html, contentDoc);
+    } catch (error) {
+      const { DOMException } = contentDoc._globalObject;
+
+      if (
+        error.constructor.name === "DOMException" &&
+        error.code === DOMException.SYNTAX_ERR &&
+        contentDoc._parsingMode === "xml"
+      ) {
+        // As defined (https://html.spec.whatwg.org/#read-xml) parsing error in XML document may be reported inline by
+        // mutating the document.
+        const element = contentDoc.createElementNS("http://www.mozilla.org/newlayout/xml/parsererror.xml", "parsererror");
+        element.textContent = error.message;
+
+        while (contentDoc.childNodes.length > 0) {
+          contentDoc.removeChild(contentDoc.lastChild);
+        }
+        contentDoc.appendChild(element);
+      } else {
+        throw error;
+      }
+    }
+
+    contentDoc.close();
+
+    return new Promise((resolve, reject) => {
+      contentDoc.addEventListener("load", resolve);
+      contentDoc.addEventListener("error", reject);
+    });
+  }
+
+  request = resourceLoader.fetch(serializedURL, {
+    element: frame,
+    onLoad: onFrameLoaded
+  });
+}
+
+function canDispatchEvents(frame, attaching) {
+  if (!attaching) {
+    return false;
+  }
+
+  return Object.keys(frame._eventListeners).length === 0;
+}
+
+function loadFrame(frame, attaching) {
+  if (frame._contentDocument) {
+    if (frame._contentDocument._defaultView) {
+      // close calls delete on its document.
+      frame._contentDocument._defaultView.close();
+    } else {
+      delete frame._contentDocument;
+    }
+  }
+
+  const parentDoc = frame._ownerDocument;
+
+  // https://html.spec.whatwg.org/#process-the-iframe-attributes
+  let url;
+  const srcAttribute = getAttributeValue(frame, "src");
+  if (srcAttribute === "") {
+    url = parseURL("about:blank");
+  } else {
+    url = parseURL(srcAttribute, { baseURL: documentBaseURL(parentDoc) || undefined }) || parseURL("about:blank");
+  }
+  const serializedURL = serializeURL(url);
+
+  const wnd = window.createWindow({
+    parsingMode: "html",
+    url: url.scheme === "javascript" ? parentDoc.URL : serializedURL,
+    parentOrigin: parentDoc._origin,
+    resourceLoader: parentDoc._defaultView._resourceLoader,
+    referrer: parentDoc.URL,
+    cookieJar: parentDoc._cookieJar,
+    pool: parentDoc._pool,
+    encoding: parentDoc._encoding,
+    runScripts: parentDoc._defaultView._runScripts,
+    commonForOrigin: parentDoc._defaultView._commonForOrigin,
+    pretendToBeVisual: parentDoc._defaultView._pretendToBeVisual
+  });
+
+  const contentDoc = frame._contentDocument = idlUtils.implForWrapper(wnd._document);
+  const parent = parentDoc._defaultView;
+  const contentWindow = contentDoc._defaultView;
+  contentWindow._parent = parent;
+  contentWindow._top = parent.top;
+  contentWindow._frameElement = frame;
+  contentWindow._virtualConsole = parent._virtualConsole;
+
+  if (parentDoc._origin === contentDoc._origin) {
+    contentWindow._currentOriginData.windowsInSameOrigin.push(contentWindow);
+  }
+
+  const noQueue = canDispatchEvents(frame, attaching);
+
+  // Handle about:blank with a simulated load of an empty document.
+  if (serializedURL === "about:blank") {
+    // Cannot be done inside the enqueued callback; the documentElement etc. need to be immediately available.
+    parseIntoDocument("<html><head></head><body></body></html>", contentDoc);
+    contentDoc.close(noQueue);
+
+    if (noQueue) {
+      fireLoadEvent(parentDoc, frame, noQueue);
+    } else {
+      contentDoc.addEventListener("load", () => {
+        fireLoadEvent(parentDoc, frame);
+      });
+    }
+  } else if (url.scheme === "javascript") {
+    // Cannot be done inside the enqueued callback; the documentElement etc. need to be immediately available.
+    parseIntoDocument("<html><head></head><body></body></html>", contentDoc);
+    contentDoc.close(noQueue);
+    const result = evaluateJavaScriptURL(contentWindow, url);
+    if (typeof result === "string") {
+      contentDoc.body.textContent = result;
+    }
+    if (noQueue) {
+      fireLoadEvent(parentDoc, frame, noQueue);
+    } else {
+      contentDoc.addEventListener("load", () => {
+        fireLoadEvent(parentDoc, frame);
+      });
+    }
+  } else {
+    fetchFrame(serializedURL, frame, parentDoc, contentDoc);
+  }
+}
+
+function refreshAccessors(document) {
+  const { _defaultView } = document;
+
+  if (!_defaultView) {
+    return;
+  }
+
+  const frames = document.querySelectorAll("iframe,frame");
+
+  // delete accessors for all frames
+  for (let i = 0; i < _defaultView._length; ++i) {
+    delete _defaultView[i];
+  }
+
+  _defaultView._length = frames.length;
+  Array.prototype.forEach.call(frames, (frame, i) => {
+    Object.defineProperty(_defaultView, i, {
+      configurable: true,
+      enumerable: true,
+      get() {
+        return frame.contentWindow;
+      }
+    });
+  });
+}
+
+class HTMLFrameElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._contentDocument = null;
+  }
+  _attrModified(name, value, oldVal) {
+    super._attrModified(name, value, oldVal);
+    if (name === "src") {
+      // iframe should never load in a document without a Window
+      // (e.g. implementation.createHTMLDocument)
+      if (this._attached && this._ownerDocument._defaultView) {
+        loadFrame(this);
+      }
+    }
+  }
+
+  _detach() {
+    super._detach();
+
+    if (this.contentWindow) {
+      this.contentWindow.close();
+    }
+
+    refreshAccessors(this._ownerDocument);
+  }
+
+  _attach() {
+    super._attach();
+
+    if (this._ownerDocument._defaultView) {
+      loadFrame(this, true);
+    }
+    refreshAccessors(this._ownerDocument);
+  }
+
+  get contentDocument() {
+    return this._contentDocument;
+  }
+
+  get contentWindow() {
+    return this.contentDocument ? this.contentDocument._defaultView : null;
+  }
+}
+
+module.exports = {
+  implementation: HTMLFrameElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFrameSetElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+const { mixin } = require("../../utils");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const WindowEventHandlersImpl = require("./WindowEventHandlers-impl").implementation;
+
+class HTMLFrameSetElementImpl extends HTMLElementImpl {
+  constructor(...args) {
+    super(...args);
+    this._proxyWindowEventsToWindow();
+  }
+}
+
+mixin(HTMLFrameSetElementImpl.prototype, WindowEventHandlersImpl.prototype);
+
+module.exports = {
+  implementation: HTMLFrameSetElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHRElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHRElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLHRElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHeadElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLHeadElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHeadingElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHeadingElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLHeadingElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHtmlElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLHtmlElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLHtmlElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,371 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const { asciiCaseInsensitiveMatch } = require("../helpers/strings");
+const { navigate } = require("../window/navigation");
+
+exports.implementation = class HTMLHyperlinkElementUtilsImpl {
+  _htmlHyperlinkElementUtilsSetup() {
+    this.url = null;
+  }
+
+  // https://html.spec.whatwg.org/multipage/links.html#cannot-navigate
+  _cannotNavigate() {
+    // TODO: Correctly check if the document is fully active
+    return this._localName !== "a" && !this.isConnected;
+  }
+
+  // https://html.spec.whatwg.org/multipage/semantics.html#get-an-element's-target
+  _getAnElementsTarget() {
+    if (this.hasAttributeNS(null, "target")) {
+      return this.getAttributeNS(null, "target");
+    }
+
+    const baseEl = this._ownerDocument.querySelector("base[target]");
+
+    if (baseEl) {
+      return baseEl.getAttributeNS(null, "target");
+    }
+
+    return "";
+  }
+
+  // https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name
+  _chooseABrowsingContext(name, current) {
+    let chosen = null;
+
+    if (name === "" || asciiCaseInsensitiveMatch(name, "_self")) {
+      chosen = current;
+    } else if (asciiCaseInsensitiveMatch(name, "_parent")) {
+      chosen = current.parent;
+    } else if (asciiCaseInsensitiveMatch(name, "_top")) {
+      chosen = current.top;
+    } else if (!asciiCaseInsensitiveMatch(name, "_blank")) {
+      // https://github.com/whatwg/html/issues/1440
+    }
+
+    // TODO: Create new browsing context, handle noopener
+
+    return chosen;
+  }
+
+  // https://html.spec.whatwg.org/multipage/links.html#following-hyperlinks-2
+  _followAHyperlink() {
+    if (this._cannotNavigate()) {
+      return;
+    }
+
+    const source = this._ownerDocument._defaultView;
+    let targetAttributeValue = "";
+
+    if (this._localName === "a" || this._localName === "area") {
+      targetAttributeValue = this._getAnElementsTarget();
+    }
+
+    const noopener = this.relList.contains("noreferrer") || this.relList.contains("noopener");
+
+    const target = this._chooseABrowsingContext(targetAttributeValue, source, noopener);
+
+    if (target === null) {
+      return;
+    }
+
+    const url = parseURLToResultingURLRecord(this.href, this._ownerDocument);
+
+    if (url === null) {
+      return;
+    }
+
+    // TODO: Handle hyperlink suffix and referrerpolicy
+    setTimeout(() => {
+      navigate(target, url, {});
+    }, 0);
+  }
+
+  toString() {
+    return this.href;
+  }
+
+  get href() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null) {
+      const href = this.getAttributeNS(null, "href");
+      return href === null ? "" : href;
+    }
+
+    return whatwgURL.serializeURL(url);
+  }
+
+  set href(v) {
+    this.setAttributeNS(null, "href", v);
+  }
+
+  get origin() {
+    reinitializeURL(this);
+
+    if (this.url === null) {
+      return "";
+    }
+
+    return whatwgURL.serializeURLOrigin(this.url);
+  }
+
+  get protocol() {
+    reinitializeURL(this);
+
+    if (this.url === null) {
+      return ":";
+    }
+
+    return this.url.scheme + ":";
+  }
+
+  set protocol(v) {
+    reinitializeURL(this);
+
+    if (this.url === null) {
+      return;
+    }
+
+    whatwgURL.basicURLParse(v + ":", { url: this.url, stateOverride: "scheme start" });
+    updateHref(this);
+  }
+
+  get username() {
+    reinitializeURL(this);
+
+    if (this.url === null) {
+      return "";
+    }
+
+    return this.url.username;
+  }
+
+  set username(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file") {
+      return;
+    }
+
+    whatwgURL.setTheUsername(url, v);
+    updateHref(this);
+  }
+
+  get password() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null) {
+      return "";
+    }
+
+    return url.password;
+  }
+
+  set password(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file") {
+      return;
+    }
+
+    whatwgURL.setThePassword(url, v);
+    updateHref(this);
+  }
+
+  get host() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.host === null) {
+      return "";
+    }
+
+    if (url.port === null) {
+      return whatwgURL.serializeHost(url.host);
+    }
+
+    return whatwgURL.serializeHost(url.host) + ":" + whatwgURL.serializeInteger(url.port);
+  }
+
+  set host(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.cannotBeABaseURL) {
+      return;
+    }
+
+    whatwgURL.basicURLParse(v, { url, stateOverride: "host" });
+    updateHref(this);
+  }
+
+  get hostname() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.host === null) {
+      return "";
+    }
+
+    return whatwgURL.serializeHost(url.host);
+  }
+
+  set hostname(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.cannotBeABaseURL) {
+      return;
+    }
+
+    whatwgURL.basicURLParse(v, { url, stateOverride: "hostname" });
+    updateHref(this);
+  }
+
+  get port() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.port === null) {
+      return "";
+    }
+
+    return whatwgURL.serializeInteger(url.port);
+  }
+
+  set port(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.host === null || url.host === "" || url.cannotBeABaseURL || url.scheme === "file") {
+      return;
+    }
+
+    if (v === "") {
+      url.port = null;
+    } else {
+      whatwgURL.basicURLParse(v, { url, stateOverride: "port" });
+    }
+    updateHref(this);
+  }
+
+  get pathname() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null) {
+      return "";
+    }
+
+    if (url.cannotBeABaseURL) {
+      return url.path[0];
+    }
+
+    return "/" + url.path.join("/");
+  }
+
+  set pathname(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.cannotBeABaseURL) {
+      return;
+    }
+
+    url.path = [];
+    whatwgURL.basicURLParse(v, { url, stateOverride: "path start" });
+    updateHref(this);
+  }
+
+  get search() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.query === null || url.query === "") {
+      return "";
+    }
+
+    return "?" + url.query;
+  }
+
+  set search(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null) {
+      return;
+    }
+
+    if (v === "") {
+      url.query = null;
+    } else {
+      const input = v[0] === "?" ? v.substring(1) : v;
+      url.query = "";
+      whatwgURL.basicURLParse(input, {
+        url,
+        stateOverride: "query",
+        encodingOverride: this._ownerDocument.charset
+      });
+    }
+    updateHref(this);
+  }
+
+  get hash() {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null || url.fragment === null || url.fragment === "") {
+      return "";
+    }
+
+    return "#" + url.fragment;
+  }
+
+  set hash(v) {
+    reinitializeURL(this);
+    const { url } = this;
+
+    if (url === null) {
+      return;
+    }
+
+    if (v === "") {
+      url.fragment = null;
+    } else {
+      const input = v[0] === "#" ? v.substring(1) : v;
+      url.fragment = "";
+      whatwgURL.basicURLParse(input, { url, stateOverride: "fragment" });
+    }
+    updateHref(this);
+  }
+};
+
+function reinitializeURL(hheu) {
+  if (hheu.url !== null && hheu.url.scheme === "blob" && hheu.url.cannotBeABaseURL) {
+    return;
+  }
+
+  setTheURL(hheu);
+}
+
+function setTheURL(hheu) {
+  const href = hheu.getAttributeNS(null, "href");
+  if (href === null) {
+    hheu.url = null;
+    return;
+  }
+
+  const parsed = parseURLToResultingURLRecord(href, hheu._ownerDocument);
+
+  hheu.url = parsed === null ? null : parsed;
+}
+
+function updateHref(hheu) {
+  hheu.setAttributeNS(null, "href", whatwgURL.serializeURL(hheu.url));
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLIFrameElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLFrameElementImpl = require("./HTMLFrameElement-impl").implementation;
+
+class HTMLIFrameElementImpl extends HTMLFrameElementImpl { }
+
+module.exports = {
+  implementation: HTMLIFrameElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLImageElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,132 @@
+"use strict";
+const conversions = require("webidl-conversions");
+const { serializeURL } = require("whatwg-url");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { Canvas } = require("../../utils");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+
+class HTMLImageElementImpl extends HTMLElementImpl {
+  constructor(...args) {
+    super(...args);
+    this._currentRequestState = "unavailable";
+  }
+
+  _attrModified(name, value, oldVal) {
+    // TODO: handle crossorigin
+    if (name === "src" || ((name === "srcset" || name === "width" || name === "sizes") && value !== oldVal)) {
+      this._updateTheImageData();
+    }
+
+    super._attrModified(name, value, oldVal);
+  }
+
+  get _accept() {
+    return "image/png,image/*;q=0.8,*/*;q=0.5";
+  }
+
+  get height() {
+    // Just like on browsers, if no width / height is defined, we fall back on the
+    // dimensions of the internal image data.
+    return this.hasAttributeNS(null, "height") ?
+           conversions["unsigned long"](this.getAttributeNS(null, "height")) :
+           this.naturalHeight;
+  }
+
+  set height(V) {
+    this.setAttributeNS(null, "height", String(V));
+  }
+
+  get width() {
+    return this.hasAttributeNS(null, "width") ?
+           conversions["unsigned long"](this.getAttributeNS(null, "width")) :
+           this.naturalWidth;
+  }
+
+  set width(V) {
+    this.setAttributeNS(null, "width", String(V));
+  }
+
+  get naturalHeight() {
+    return this._image ? this._image.naturalHeight : 0;
+  }
+
+  get naturalWidth() {
+    return this._image ? this._image.naturalWidth : 0;
+  }
+
+  get complete() {
+    const srcAttributeValue = this.getAttributeNS(null, "src");
+    return srcAttributeValue === null ||
+      srcAttributeValue === "" ||
+      this._currentRequestState === "broken" ||
+      this._currentRequestState === "completely available";
+  }
+
+  get currentSrc() {
+    return this._currentSrc || "";
+  }
+
+  // https://html.spec.whatwg.org/multipage/images.html#updating-the-image-data
+  _updateTheImageData() {
+    const document = this._ownerDocument;
+
+    if (!document._defaultView) {
+      return;
+    }
+
+    if (!Canvas) {
+      return;
+    }
+
+    if (!this._image) {
+      this._image = new Canvas.Image();
+    }
+    this._currentSrc = null;
+    this._currentRequestState = "unavailable";
+    const srcAttributeValue = this.getAttributeNS(null, "src");
+    let urlString = null;
+    if (srcAttributeValue !== null && srcAttributeValue !== "") {
+      const urlRecord = parseURLToResultingURLRecord(srcAttributeValue, this._ownerDocument);
+      if (urlRecord === null) {
+        return;
+      }
+      urlString = serializeURL(urlRecord);
+    }
+    if (urlString !== null) {
+      const resourceLoader = document._resourceLoader;
+      let request;
+
+      const onLoadImage = data => {
+        const { response } = request;
+
+        if (response && response.statusCode !== undefined && response.statusCode !== 200) {
+          throw new Error("Status code: " + response.statusCode);
+        }
+        let error = null;
+        this._image.onerror = function (err) {
+          error = err;
+        };
+        this._image.src = data;
+        if (error) {
+          throw new Error(error);
+        }
+        this._currentSrc = srcAttributeValue;
+        this._currentRequestState = "completely available";
+      };
+
+      request = resourceLoader.fetch(urlString, {
+        element: this,
+        onLoad: onLoadImage,
+        onError: () => {
+          this._currentRequestState = "broken";
+        }
+      });
+    } else {
+      this._image.src = "";
+    }
+  }
+}
+
+module.exports = {
+  implementation: HTMLImageElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLInputElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1128 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const FileList = require("../generated/FileList");
+const Decimal = require("decimal.js");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const idlUtils = require("../generated/utils");
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const ValidityState = require("../generated/ValidityState");
+const { mixin } = require("../../utils");
+const { domSymbolTree, cloningSteps } = require("../helpers/internal-constants");
+const { getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+const { fireAnEvent } = require("../helpers/events");
+const {
+  isDisabled,
+  isValidEmailAddress,
+  isValidAbsoluteURL,
+  sanitizeValueByType
+} = require("../helpers/form-controls");
+const {
+  asciiCaseInsensitiveMatch,
+  asciiLowercase,
+  parseFloatingPointNumber,
+  splitOnCommas
+} = require("../helpers/strings");
+const { isDate } = require("../helpers/dates-and-times");
+const {
+  convertStringToNumberByType,
+  convertStringToDateByType,
+  serializeDateByType,
+  convertNumberToStringByType
+} = require("../helpers/number-and-date-inputs");
+
+const filesSymbol = Symbol("files");
+
+// https://html.spec.whatwg.org/multipage/input.html#attr-input-type
+const inputAllowedTypes = new Set([
+  "hidden", "text", "search", "tel", "url", "email", "password", "date",
+  "month", "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio",
+  "file", "submit", "image", "reset", "button"
+]);
+
+// https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
+
+const variableLengthSelectionAllowedTypes = new Set(["text", "search", "url", "tel", "password"]);
+const numericTypes = new Set(["date", "month", "week", "time", "datetime-local", "number", "range"]);
+
+const applicableTypesForIDLMember = {
+  valueAsDate: new Set(["date", "month", "week", "time"]),
+  valueAsNumber: numericTypes,
+
+  select: new Set([
+    "text", "search", "url", "tel", "email", "password", "date", "month", "week",
+    "time", "datetime-local", "number", "color", "file"
+  ]),
+  selectionStart: variableLengthSelectionAllowedTypes,
+  selectionEnd: variableLengthSelectionAllowedTypes,
+  selectionDirection: variableLengthSelectionAllowedTypes,
+  setRangeText: variableLengthSelectionAllowedTypes,
+  setSelectionRange: variableLengthSelectionAllowedTypes,
+  stepDown: numericTypes,
+  stepUp: numericTypes
+};
+
+const lengthPatternSizeTypes = new Set(["text", "search", "url", "tel", "email", "password"]);
+const readonlyTypes =
+  new Set([...lengthPatternSizeTypes, "date", "month", "week", "time", "datetime-local", "number"]);
+
+const applicableTypesForContentAttribute = {
+  list: new Set(["text", "search", "url", "tel", "email", ...numericTypes, "color"]),
+  max: numericTypes,
+  maxlength: lengthPatternSizeTypes,
+  min: numericTypes,
+  minlength: lengthPatternSizeTypes,
+  multiple: new Set(["email", "file"]),
+  pattern: lengthPatternSizeTypes,
+  readonly: readonlyTypes,
+  required: new Set([...readonlyTypes, "checkbox", "radio", "file"]),
+  step: numericTypes
+};
+
+const valueAttributeDefaultMode = new Set(["hidden", "submit", "image", "reset", "button"]);
+const valueAttributeDefaultOnMode = new Set(["checkbox", "radio"]);
+
+function valueAttributeMode(type) {
+  if (valueAttributeDefaultMode.has(type)) {
+    return "default";
+  }
+  if (valueAttributeDefaultOnMode.has(type)) {
+    return "default/on";
+  }
+  if (type === "file") {
+    return "filename";
+  }
+  return "value";
+}
+
+function getTypeFromAttribute(typeAttribute) {
+  if (typeof typeAttribute !== "string") {
+    return "text";
+  }
+  const type = asciiLowercase(typeAttribute);
+  return inputAllowedTypes.has(type) ? type : "text";
+}
+
+class HTMLInputElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._selectionStart = this._selectionEnd = 0;
+    this._selectionDirection = "none";
+    this._value = "";
+    this._dirtyValue = false;
+    this._checkedness = false;
+    this._dirtyCheckedness = false;
+
+    this._preCheckedRadioState = null;
+    this._legacyActivationBehaviorPreviousIndeterminateState = false;
+
+    this.indeterminate = false;
+
+    this._customValidityErrorMessage = "";
+
+    this._labels = null;
+
+    this._hasActivationBehavior = true;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-value-string-number
+  get _convertStringToNumber() {
+    return convertStringToNumberByType[this.type];
+  }
+
+  get _convertNumberToString() {
+    return convertNumberToStringByType[this.type];
+  }
+
+  get _convertDateToString() {
+    return serializeDateByType[this.type];
+  }
+
+  get _convertStringToDate() {
+    return convertStringToDateByType[this.type];
+  }
+
+  _isStepAligned(v) {
+    return new Decimal(v).minus(this._stepBase)
+      .modulo(this._allowedValueStep)
+      .isZero();
+  }
+
+  // Returns a Decimal.
+  _stepAlign(v, roundUp) {
+    const allowedValueStep = this._allowedValueStep;
+    const stepBase = this._stepBase;
+
+    return new Decimal(v).minus(stepBase)
+      .toNearest(allowedValueStep, roundUp ? Decimal.ROUND_UP : Decimal.ROUND_DOWN)
+      .add(stepBase);
+  }
+
+  // For <input>, https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-value
+  // is a simple value that is gotten and set, not computed.
+  _getValue() {
+    return this._value;
+  }
+
+  _legacyPreActivationBehavior() {
+    if (this.type === "checkbox") {
+      this.checked = !this.checked;
+      this._legacyActivationBehaviorPreviousIndeterminateState = this.indeterminate;
+      this.indeterminate = false;
+    } else if (this.type === "radio") {
+      this._preCheckedRadioState = this.checked;
+      this.checked = true;
+    }
+  }
+
+  _legacyCanceledActivationBehavior() {
+    if (this.type === "checkbox") {
+      this.checked = !this.checked;
+      this.indeterminate = this._legacyActivationBehaviorPreviousIndeterminateState;
+    } else if (this.type === "radio") {
+      if (this._preCheckedRadioState !== null) {
+        this.checked = this._preCheckedRadioState;
+        this._preCheckedRadioState = null;
+      }
+    }
+  }
+
+  _activationBehavior() {
+    if (!this._mutable && this.type !== "checkbox" && this.type !== "radio") {
+      return;
+    }
+
+    const { form } = this;
+
+    if (this.type === "checkbox" || (this.type === "radio" && !this._preCheckedRadioState)) {
+      if (this.isConnected) {
+        fireAnEvent("input", this, undefined, { bubbles: true });
+        fireAnEvent("change", this, undefined, { bubbles: true });
+      }
+    } else if (form && this.type === "submit") {
+      form._doSubmit();
+    } else if (form && this.type === "reset") {
+      form._doReset();
+    }
+  }
+
+  _attrModified(name, value, oldVal) {
+    const wrapper = idlUtils.wrapperForImpl(this);
+    if (!this._dirtyValue && name === "value") {
+      this._value = sanitizeValueByType(this, wrapper.defaultValue);
+    }
+    if (!this._dirtyCheckedness && name === "checked") {
+      this._checkedness = wrapper.defaultChecked;
+      if (this._checkedness) {
+        this._removeOtherRadioCheckedness();
+      }
+    }
+
+    if (name === "name" || name === "type") {
+      if (this._checkedness) {
+        this._removeOtherRadioCheckedness();
+      }
+    }
+
+    if (name === "type") {
+      const prevType = getTypeFromAttribute(oldVal);
+      const curType = getTypeFromAttribute(value);
+      // When an input element's type attribute changes state…
+      if (prevType !== curType) {
+        const prevValueMode = valueAttributeMode(prevType);
+        const curValueMode = valueAttributeMode(curType);
+        if (prevValueMode === "value" && this._value !== "" &&
+            (curValueMode === "default" || curValueMode === "default/on")) {
+          this.setAttributeNS(null, "value", this._value);
+        } else if (prevValueMode !== "value" && curValueMode === "value") {
+          this._value = this.getAttributeNS(null, "value") || "";
+          this._dirtyValue = false;
+        } else if (prevValueMode !== "filename" && curValueMode === "filename") {
+          this._value = "";
+        }
+
+        this._signalATypeChange();
+
+        this._value = sanitizeValueByType(this, this._value);
+
+        const previouslySelectable = this._idlMemberApplies("setRangeText", prevType);
+        const nowSelectable = this._idlMemberApplies("setRangeText", curType);
+        if (!previouslySelectable && nowSelectable) {
+          this._selectionStart = 0;
+          this._selectionEnd = 0;
+          this._selectionDirection = "none";
+        }
+      }
+    }
+
+    super._attrModified(name, value, oldVal);
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#signal-a-type-change
+  _signalATypeChange() {
+    if (this._checkedness) {
+      this._removeOtherRadioCheckedness();
+    }
+  }
+
+  _formReset() {
+    const wrapper = idlUtils.wrapperForImpl(this);
+    this._value = sanitizeValueByType(this, wrapper.defaultValue);
+    this._dirtyValue = false;
+    this._checkedness = wrapper.defaultChecked;
+    this._dirtyCheckedness = false;
+    if (this._checkedness) {
+      this._removeOtherRadioCheckedness();
+    }
+  }
+
+  _changedFormOwner() {
+    if (this._checkedness) {
+      this._removeOtherRadioCheckedness();
+    }
+  }
+
+  get _otherRadioGroupElements() {
+    const wrapper = idlUtils.wrapperForImpl(this);
+    const root = this._radioButtonGroupRoot;
+    if (!root) {
+      return [];
+    }
+
+    const result = [];
+
+    const descendants = domSymbolTree.treeIterator(root);
+    for (const candidate of descendants) {
+      if (candidate._radioButtonGroupRoot !== root) {
+        continue;
+      }
+
+      const candidateWrapper = idlUtils.wrapperForImpl(candidate);
+      if (!candidateWrapper.name || candidateWrapper.name !== wrapper.name) {
+        continue;
+      }
+
+      if (candidate !== this) {
+        result.push(candidate);
+      }
+    }
+    return result;
+  }
+
+  _removeOtherRadioCheckedness() {
+    for (const radioGroupElement of this._otherRadioGroupElements) {
+      radioGroupElement._checkedness = false;
+    }
+  }
+
+  get _radioButtonGroupRoot() {
+    const wrapper = idlUtils.wrapperForImpl(this);
+    if (this.type !== "radio" || !wrapper.name) {
+      return null;
+    }
+
+    let e = domSymbolTree.parent(this);
+    while (e) {
+      // root node of this home sub tree
+      // or the form element we belong to
+      if (!domSymbolTree.parent(e) || e.nodeName.toUpperCase() === "FORM") {
+        return e;
+      }
+      e = domSymbolTree.parent(e);
+    }
+    return null;
+  }
+
+  _someInRadioGroup(name) {
+    if (this[name]) {
+      return true;
+    }
+    return this._otherRadioGroupElements.some(radioGroupElement => radioGroupElement[name]);
+  }
+
+  get _mutable() {
+    return !isDisabled(this) && !this._hasAttributeAndApplies("readonly");
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get checked() {
+    return this._checkedness;
+  }
+
+  set checked(checked) {
+    this._checkedness = Boolean(checked);
+    this._dirtyCheckedness = true;
+    if (this._checkedness) {
+      this._removeOtherRadioCheckedness();
+    }
+  }
+
+  get value() {
+    switch (valueAttributeMode(this.type)) {
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
+      case "value":
+        return this._getValue();
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default
+      case "default": {
+        const attr = this.getAttributeNS(null, "value");
+        return attr !== null ? attr : "";
+      }
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
+      case "default/on": {
+        const attr = this.getAttributeNS(null, "value");
+        return attr !== null ? attr : "on";
+      }
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename
+      case "filename":
+        return this.files.length ? "C:\\fakepath\\" + this.files[0].name : "";
+      default:
+        throw new Error("jsdom internal error: unknown value attribute mode");
+    }
+  }
+
+  set value(val) {
+    switch (valueAttributeMode(this.type)) {
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-value
+      case "value": {
+        const oldValue = this._value;
+        this._value = sanitizeValueByType(this, val);
+        this._dirtyValue = true;
+
+        if (oldValue !== this._value) {
+          this._selectionStart = this._selectionEnd = this._getValueLength();
+          this._selectionDirection = "none";
+        }
+        break;
+      }
+
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-default-on
+      case "default":
+      case "default/on":
+        this.setAttributeNS(null, "value", val);
+        break;
+
+      // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename
+      case "filename":
+        if (val === "") {
+          this.files.length = 0;
+        } else {
+          throw DOMException.create(this._globalObject, [
+            "This input element accepts a filename, which may only be programmatically set to the empty string.",
+            "InvalidStateError"
+          ]);
+        }
+        break;
+
+      default:
+        throw new Error("jsdom internal error: unknown value attribute mode");
+    }
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasdate
+  get valueAsDate() {
+    if (!this._idlMemberApplies("valueAsDate")) {
+      return null;
+    }
+
+    const window = this._ownerDocument._defaultView;
+    const convertedValue = this._convertStringToDate(this._value);
+
+    if (convertedValue instanceof Date) {
+      return new window.Date(convertedValue.getTime());
+    }
+
+    return null;
+  }
+
+  set valueAsDate(v) {
+    if (!this._idlMemberApplies("valueAsDate")) {
+      throw DOMException.create(this._globalObject, [
+        "Failed to set the 'valueAsDate' property on 'HTMLInputElement': This input element does not support Date " +
+        "values.",
+        "InvalidStateError"
+      ]);
+    }
+
+    if (v !== null && !isDate(v)) {
+      throw new TypeError("Failed to set the 'valueAsDate' property on 'HTMLInputElement': The provided value is " +
+        "not a Date.");
+    }
+
+    if (v === null || isNaN(v)) {
+      this._value = "";
+    }
+
+    this._value = this._convertDateToString(v);
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#dom-input-valueasnumber
+  get valueAsNumber() {
+    if (!this._idlMemberApplies("valueAsNumber")) {
+      return NaN;
+    }
+
+    const parsedValue = this._convertStringToNumber(this._value);
+    return parsedValue !== null ? parsedValue : NaN;
+  }
+
+  set valueAsNumber(v) {
+    if (!isFinite(v)) {
+      throw new TypeError("Failed to set infinite value as Number");
+    }
+
+    if (!this._idlMemberApplies("valueAsNumber")) {
+      throw DOMException.create(this._globalObject, [
+        "Failed to set the 'valueAsNumber' property on 'HTMLInputElement': This input element does not support " +
+        "Number values.",
+        "InvalidStateError"
+      ]);
+    }
+
+    this._value = this._convertNumberToString(v);
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#dom-input-stepup
+  _stepUpdate(n, isUp) {
+    const methodName = isUp ? "stepUp" : "stepDown";
+    if (!this._idlMemberApplies(methodName)) {
+      throw DOMException.create(this._globalObject, [
+        `Failed to invoke '${methodName}' method on 'HTMLInputElement': ` +
+        "This input element does not support Number values.",
+        "InvalidStateError"
+      ]);
+    }
+
+    const allowedValueStep = this._allowedValueStep;
+    if (allowedValueStep === null) {
+      throw DOMException.create(this._globalObject, [
+        `Failed to invoke '${methodName}' method on 'HTMLInputElement': ` +
+        "This input element does not support value step.",
+        "InvalidStateError"
+      ]);
+    }
+
+    const min = this._minimum;
+    const max = this._maximum;
+
+    if (min !== null && max !== null) {
+      if (min > max) {
+        return;
+      }
+
+      const candidateStepValue = this._stepAlign(Decimal.add(min, allowedValueStep), /* roundUp = */ false);
+      if (candidateStepValue.lt(min) || candidateStepValue.gt(max)) {
+        return;
+      }
+    }
+
+    let value = 0;
+    try {
+      value = this.valueAsNumber;
+      if (isNaN(value)) { // Empty value is parsed as NaN.
+        value = 0;
+      }
+    } catch (error) {
+      // Step 5. Default value is 0.
+    }
+    value = new Decimal(value);
+
+    const valueBeforeStepping = value;
+
+    if (!this._isStepAligned(value)) {
+      value = this._stepAlign(value, /* roundUp = */ isUp);
+    } else {
+      let delta = Decimal.mul(n, allowedValueStep);
+      if (!isUp) {
+        delta = delta.neg();
+      }
+      value = value.add(delta);
+    }
+
+    if (min !== null && value.lt(min)) {
+      value = this._stepAlign(min, /* roundUp = */ true);
+    }
+
+    if (max !== null && value.gt(max)) {
+      value = this._stepAlign(max, /* roundUp = */ false);
+    }
+
+    if (isUp ? value.lt(valueBeforeStepping) : value.gt(valueBeforeStepping)) {
+      return;
+    }
+
+    this._value = this._convertNumberToString(value.toNumber());
+  }
+
+  stepDown(n = 1) {
+    return this._stepUpdate(n, false);
+  }
+
+  stepUp(n = 1) {
+    return this._stepUpdate(n, true);
+  }
+
+  get files() {
+    if (this.type === "file") {
+      this[filesSymbol] = this[filesSymbol] || FileList.createImpl(this._globalObject);
+    } else {
+      this[filesSymbol] = null;
+    }
+    return this[filesSymbol];
+  }
+
+  set files(value) {
+    if (this.type === "file" && value !== null) {
+      this[filesSymbol] = value;
+    }
+  }
+
+  get type() {
+    const typeAttribute = this.getAttributeNS(null, "type");
+    return getTypeFromAttribute(typeAttribute);
+  }
+
+  set type(type) {
+    this.setAttributeNS(null, "type", type);
+  }
+
+  _dispatchSelectEvent() {
+    fireAnEvent("select", this, undefined, { bubbles: true, cancelable: true });
+  }
+
+  _getValueLength() {
+    return typeof this.value === "string" ? this.value.length : 0;
+  }
+
+  select() {
+    if (!this._idlMemberApplies("select")) {
+      return;
+    }
+
+    this._selectionStart = 0;
+    this._selectionEnd = this._getValueLength();
+    this._selectionDirection = "none";
+    this._dispatchSelectEvent();
+  }
+
+  get selectionStart() {
+    if (!this._idlMemberApplies("selectionStart")) {
+      return null;
+    }
+
+    return this._selectionStart;
+  }
+
+  set selectionStart(start) {
+    if (!this._idlMemberApplies("selectionStart")) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
+  }
+
+  get selectionEnd() {
+    if (!this._idlMemberApplies("selectionEnd")) {
+      return null;
+    }
+
+    return this._selectionEnd;
+  }
+
+  set selectionEnd(end) {
+    if (!this._idlMemberApplies("selectionEnd")) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
+  }
+
+  get selectionDirection() {
+    if (!this._idlMemberApplies("selectionDirection")) {
+      return null;
+    }
+
+    return this._selectionDirection;
+  }
+
+  set selectionDirection(dir) {
+    if (!this._idlMemberApplies("selectionDirection")) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
+  }
+
+  setSelectionRange(start, end, dir) {
+    if (!this._idlMemberApplies("setSelectionRange")) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    this._selectionEnd = Math.min(end, this._getValueLength());
+    this._selectionStart = Math.min(start, this._selectionEnd);
+    this._selectionDirection = dir === "forward" || dir === "backward" ? dir : "none";
+    this._dispatchSelectEvent();
+  }
+
+  setRangeText(repl, start, end, selectionMode = "preserve") {
+    if (!this._idlMemberApplies("setRangeText")) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    if (arguments.length < 2) {
+      start = this._selectionStart;
+      end = this._selectionEnd;
+    } else if (start > end) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+
+    start = Math.min(start, this._getValueLength());
+    end = Math.min(end, this._getValueLength());
+
+    const val = this.value;
+    let selStart = this._selectionStart;
+    let selEnd = this._selectionEnd;
+
+    this.value = val.slice(0, start) + repl + val.slice(end);
+
+    const newEnd = start + this.value.length;
+
+    if (selectionMode === "select") {
+      this.setSelectionRange(start, newEnd);
+    } else if (selectionMode === "start") {
+      this.setSelectionRange(start, start);
+    } else if (selectionMode === "end") {
+      this.setSelectionRange(newEnd, newEnd);
+    } else { // preserve
+      const delta = repl.length - (end - start);
+
+      if (selStart > end) {
+        selStart += delta;
+      } else if (selStart > start) {
+        selStart = start;
+      }
+
+      if (selEnd > end) {
+        selEnd += delta;
+      } else if (selEnd > start) {
+        selEnd = newEnd;
+      }
+
+      this.setSelectionRange(selStart, selEnd);
+    }
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#the-list-attribute
+  get list() {
+    const id = this._getAttributeIfApplies("list");
+    if (!id) {
+      return null;
+    }
+
+    const el = this.getRootNode({}).getElementById(id);
+
+    if (el && el.localName === "datalist") {
+      return el;
+    }
+
+    return null;
+  }
+
+  // Reflected IDL attribute does not care about whether the content attribute applies.
+  get maxLength() {
+    if (!this.hasAttributeNS(null, "maxlength")) {
+      return 524288; // stole this from chrome
+    }
+    return parseInt(this.getAttributeNS(null, "maxlength"));
+  }
+
+  set maxLength(value) {
+    if (value < 0) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    this.setAttributeNS(null, "maxlength", String(value));
+  }
+
+  get minLength() {
+    if (!this.hasAttributeNS(null, "minlength")) {
+      return 0;
+    }
+    return parseInt(this.getAttributeNS(null, "minlength"));
+  }
+
+  set minLength(value) {
+    if (value < 0) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    this.setAttributeNS(null, "minlength", String(value));
+  }
+
+  get size() {
+    if (!this.hasAttributeNS(null, "size")) {
+      return 20;
+    }
+    return parseInt(this.getAttributeNS(null, "size"));
+  }
+
+  set size(value) {
+    if (value <= 0) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    this.setAttributeNS(null, "size", String(value));
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
+  get _minimum() {
+    let min = this._defaultMinimum;
+    const attr = this._getAttributeIfApplies("min");
+    if (attr !== null && this._convertStringToNumber !== undefined) {
+      const parsed = this._convertStringToNumber(attr);
+      if (parsed !== null) {
+        min = parsed;
+      }
+    }
+    return min;
+  }
+
+  get _maximum() {
+    let max = this._defaultMaximum;
+    const attr = this._getAttributeIfApplies("max");
+    if (attr !== null && this._convertStringToNumber !== undefined) {
+      const parsed = this._convertStringToNumber(attr);
+      if (parsed !== null) {
+        max = parsed;
+      }
+    }
+    return max;
+  }
+
+  get _defaultMinimum() {
+    if (this.type === "range") {
+      return 0;
+    }
+    return null;
+  }
+
+  get _defaultMaximum() {
+    if (this.type === "range") {
+      return 100;
+    }
+    return null;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-step
+  get _allowedValueStep() {
+    if (!this._contentAttributeApplies("step")) {
+      return null;
+    }
+    const attr = this.getAttributeNS(null, "step");
+    if (attr === null) {
+      return this._defaultStep * this._stepScaleFactor;
+    }
+    if (asciiCaseInsensitiveMatch(attr, "any")) {
+      return null;
+    }
+    const parsedStep = parseFloatingPointNumber(attr);
+    if (parsedStep === null || parsedStep <= 0) {
+      return this._defaultStep * this._stepScaleFactor;
+    }
+    return parsedStep * this._stepScaleFactor;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-scale
+  get _stepScaleFactor() {
+    const dayInMilliseconds = 24 * 60 * 60 * 1000;
+    switch (this.type) {
+      case "week":
+        return 7 * dayInMilliseconds;
+      case "date":
+        return dayInMilliseconds;
+      case "datetime-local":
+      case "datetime":
+      case "time":
+        return 1000;
+    }
+    return 1;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-default
+  get _defaultStep() {
+    if (this.type === "datetime-local" || this.type === "datetime" || this.type === "time") {
+      return 60;
+    }
+    return 1;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-min-zero
+  get _stepBase() {
+    if (this._hasAttributeAndApplies("min")) {
+      const min = this._convertStringToNumber(this.getAttributeNS(null, "min"));
+      if (min !== null) {
+        return min;
+      }
+    }
+    if (this.hasAttributeNS(null, "value")) {
+      const value = this._convertStringToNumber(this.getAttributeNS(null, "value"));
+      if (value !== null) {
+        return value;
+      }
+    }
+    if (this._defaultStepBase !== null) {
+      return this._defaultStepBase;
+    }
+    return 0;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-step-default-base
+  get _defaultStepBase() {
+    if (this.type === "week") {
+      // The start of week 1970-W01
+      return -259200000;
+    }
+    return null;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#common-input-element-attributes
+  // When an attribute doesn't apply to an input element, user agents must ignore the attribute.
+  _contentAttributeApplies(attribute) {
+    return applicableTypesForContentAttribute[attribute].has(this.type);
+  }
+
+  _hasAttributeAndApplies(attribute) {
+    return this._contentAttributeApplies(attribute) && this.hasAttributeNS(null, attribute);
+  }
+
+  _getAttributeIfApplies(attribute) {
+    if (this._contentAttributeApplies(attribute)) {
+      return this.getAttributeNS(null, attribute);
+    }
+    return null;
+  }
+
+  _idlMemberApplies(member, type = this.type) {
+    return applicableTypesForIDLMember[member].has(type);
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    // https://html.spec.whatwg.org/multipage/input.html#hidden-state-(type=hidden)
+    // https://html.spec.whatwg.org/multipage/input.html#reset-button-state-(type=reset)
+    // https://html.spec.whatwg.org/multipage/input.html#button-state-(type=button)
+    const willNotValidateTypes = new Set(["hidden", "reset", "button"]);
+    // https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
+    const readOnly = this._hasAttributeAndApplies("readonly");
+
+    // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-disabled
+    return willNotValidateTypes.has(this.type) || readOnly;
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#concept-input-required
+  get _required() {
+    return this._hasAttributeAndApplies("required");
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#has-a-periodic-domain
+  get _hasAPeriodicDomain() {
+    return this.type === "time";
+  }
+
+  // https://html.spec.whatwg.org/multipage/input.html#has-a-reversed-range
+  get _hasAReversedRange() {
+    return this._hasAPeriodicDomain && this._maximum < this._minimum;
+  }
+
+  get validity() {
+    if (!this._validity) {
+      // Constraint validation: When an element has a reversed range, and the result of applying
+      // the algorithm to convert a string to a number to the string given by the element's value
+      // is a number, and the number obtained from that algorithm is more than the maximum and less
+      // than the minimum, the element is simultaneously suffering from an underflow and suffering
+      // from an overflow.
+      const reversedRangeSufferingOverUnderflow = () => {
+        const parsedValue = this._convertStringToNumber(this._value);
+        return parsedValue !== null && parsedValue > this._maximum && parsedValue < this._minimum;
+      };
+
+      const state = {
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-missing
+        valueMissing: () => {
+          // https://html.spec.whatwg.org/multipage/input.html#the-required-attribute
+          // Constraint validation: If the element is required, and its value IDL attribute applies
+          // and is in the mode value, and the element is mutable, and the element's value is the
+          // empty string, then the element is suffering from being missing.
+          //
+          // Note: As of today, the value IDL attribute always applies.
+          if (this._required && valueAttributeMode(this.type) === "value" && this._mutable && this._value === "") {
+            return true;
+          }
+
+          switch (this.type) {
+            // https://html.spec.whatwg.org/multipage/input.html#checkbox-state-(type=checkbox)
+            // Constraint validation: If the element is required and its checkedness is
+            // false, then the element is suffering from being missing.
+            case "checkbox":
+              if (this._required && !this._checkedness) {
+                return true;
+              }
+              break;
+
+            // https://html.spec.whatwg.org/multipage/input.html#radio-button-state-(type=radio)
+            // Constraint validation: If an element in the radio button group is required,
+            // and all of the input elements in the radio button group have a checkedness
+            // that is false, then the element is suffering from being missing.
+            case "radio":
+              if (this._someInRadioGroup("_required") && !this._someInRadioGroup("checked")) {
+                return true;
+              }
+              break;
+
+            // https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=file)
+            // Constraint validation: If the element is required and the list of selected files is
+            // empty, then the element is suffering from being missing.
+            case "file":
+              if (this._required && this.files.length === 0) {
+                return true;
+              }
+              break;
+          }
+
+          return false;
+        },
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-too-long
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-maxlength
+        // jsdom has no way at the moment to emulate a user interaction, so tooLong/tooShort have
+        // to be set to false.
+        tooLong: () => false,
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-being-too-short
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-minlength
+        tooShort: () => false,
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-overflow
+        rangeOverflow: () => {
+          // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
+          if (this._hasAReversedRange) {
+            return reversedRangeSufferingOverUnderflow();
+          }
+          // Constraint validation: When the element has a maximum and does not have a reversed
+          // range, and the result of applying the algorithm to convert a string to a number to the
+          // string given by the element's value is a number, and the number obtained from that
+          // algorithm is more than the maximum, the element is suffering from an overflow.
+          if (this._maximum !== null) {
+            const parsedValue = this._convertStringToNumber(this._value);
+            if (parsedValue !== null && parsedValue > this._maximum) {
+              return true;
+            }
+          }
+          return false;
+        },
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-an-underflow
+        rangeUnderflow: () => {
+          // https://html.spec.whatwg.org/multipage/input.html#the-min-and-max-attributes
+          if (this._hasAReversedRange) {
+            return reversedRangeSufferingOverUnderflow();
+          }
+          // Constraint validation: When the element has a minimum and does not have a reversed
+          // range, and the result of applying the algorithm to convert a string to a number to the
+          // string given by the element's value is a number, and the number obtained from that
+          // algorithm is less than the minimum, the element is suffering from an underflow.
+          if (this._minimum !== null) {
+            const parsedValue = this._convertStringToNumber(this._value);
+            if (parsedValue !== null && parsedValue < this._minimum) {
+              return true;
+            }
+          }
+          return false;
+        },
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-pattern-mismatch
+        patternMismatch: () => {
+          // https://html.spec.whatwg.org/multipage/input.html#the-pattern-attribute
+          if (this._value === "" || !this._hasAttributeAndApplies("pattern")) {
+            return false;
+          }
+          let regExp;
+          try {
+            const pattern = this.getAttributeNS(null, "pattern");
+            // The pattern attribute should be matched against the entire value, not just any
+            // subset, so add ^ and $ anchors. But also check the validity of the regex itself
+            // first.
+            new RegExp(pattern, "u"); // eslint-disable-line no-new
+            regExp = new RegExp("^(?:" + pattern + ")$", "u");
+          } catch (e) {
+            return false;
+          }
+          if (this._hasAttributeAndApplies("multiple")) {
+            return !splitOnCommas(this._value).every(value => regExp.test(value));
+          }
+          return !regExp.test(this._value);
+        },
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-step-mismatch
+        // https://html.spec.whatwg.org/multipage/input.html#attr-input-step
+        stepMismatch: () => {
+          const allowedValueStep = this._allowedValueStep;
+          if (allowedValueStep === null) {
+            return false;
+          }
+          const number = this._convertStringToNumber(this._value);
+          return number !== null && !this._isStepAligned(number);
+        },
+
+        // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#suffering-from-a-type-mismatch
+        typeMismatch: () => {
+          switch (this.type) {
+            // https://html.spec.whatwg.org/multipage/input.html#url-state-(type=url)
+            // Constraint validation: While the value of the element is neither the empty string
+            // nor a valid absolute URL, the element is suffering from a type mismatch.
+            case "url":
+              if (this._value !== "" && !isValidAbsoluteURL(this._value)) {
+                return true;
+              }
+              break;
+
+            // https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type=email)
+            // Constraint validation [multiple=false]: While the value of the element is neither the empty
+            // string nor a single valid e - mail address, the element is suffering from a type mismatch.
+            // Constraint validation [multiple=true]: While the value of the element is not a valid e-mail address list,
+            // the element is suffering from a type mismatch.
+            case "email":
+              if (this._value !== "" && !isValidEmailAddress(this._getValue(), this.hasAttributeNS(null, "multiple"))) {
+                return true;
+              }
+              break;
+          }
+          return false;
+        }
+      };
+
+      this._validity = ValidityState.createImpl(this._globalObject, [], {
+        element: this,
+        state
+      });
+    }
+    return this._validity;
+  }
+
+  [cloningSteps](copy, node) {
+    copy._value = node._value;
+    copy._checkedness = node._checkedness;
+    copy._dirtyValue = node._dirtyValue;
+    copy._dirtyCheckedness = node._dirtyCheckedness;
+  }
+}
+
+mixin(HTMLInputElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLInputElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLIElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLLIElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLLIElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLabelElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,94 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const MouseEvent = require("../generated/MouseEvent");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+const { isLabelable, isDisabled, isInteractiveContent } = require("../helpers/form-controls");
+const { isInclusiveAncestor } = require("../helpers/node");
+const { fireAnEvent } = require("../helpers/events");
+
+function sendClickToAssociatedNode(node) {
+  fireAnEvent("click", node, MouseEvent, {
+    bubbles: true,
+    cancelable: true,
+    view: node.ownerDocument ? node.ownerDocument.defaultView : null,
+    screenX: 0,
+    screenY: 0,
+    clientX: 0,
+    clientY: 0,
+    button: 0,
+    detail: 1,
+    relatedTarget: null
+  });
+}
+
+class HTMLLabelElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._hasActivationBehavior = true;
+  }
+
+  get control() {
+    if (this.hasAttributeNS(null, "for")) {
+      const forValue = this.getAttributeNS(null, "for");
+      if (forValue === "") {
+        return null;
+      }
+      const root = this.getRootNode({});
+      for (const descendant of domSymbolTree.treeIterator(root)) {
+        if (descendant.nodeType === NODE_TYPE.ELEMENT_NODE &&
+          descendant.getAttributeNS(null, "id") === forValue) {
+          return isLabelable(descendant) ? descendant : null;
+        }
+      }
+      return null;
+    }
+    for (const descendant of domSymbolTree.treeIterator(this)) {
+      if (isLabelable(descendant)) {
+        return descendant;
+      }
+    }
+    return null;
+  }
+
+  get form() {
+    const node = this.control;
+    if (node) {
+      return node.form;
+    }
+    return null;
+  }
+
+  _activationBehavior(event) {
+    // Check if the event's target is an inclusive descendant of any interactive content descendant of this <label>.
+    // If so, do nothing.
+    if (event.target && event.target !== this && isInclusiveAncestor(this, event.target)) {
+      for (const ancestor of domSymbolTree.ancestorsIterator(event.target)) {
+        if (ancestor === this) {
+          break;
+        }
+        if (isInteractiveContent(ancestor)) {
+          return;
+        }
+      }
+    }
+
+    const node = this.control;
+    if (node && !isDisabled(node)) {
+      // Check if the control is an inclusive ancestor of the event's target (and has already received this event).
+      // If so, do nothing.
+      // See https://github.com/whatwg/html/issues/5415.
+      if (event.target && isInclusiveAncestor(node, event.target)) {
+        return;
+      }
+
+      sendClickToAssociatedNode(node);
+    }
+  }
+}
+
+module.exports = {
+  implementation: HTMLLabelElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLegendElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { formOwner } = require("../helpers/form-controls");
+const { HTML_NS } = require("../helpers/namespaces");
+
+class HTMLLegendElementImpl extends HTMLElementImpl {
+  get form() {
+    const parent = this.parentNode;
+    if (parent && parent._localName === "fieldset" && parent.namespaceURI === HTML_NS) {
+      return formOwner(parent);
+    }
+    return null;
+  }
+}
+
+module.exports = {
+  implementation: HTMLLegendElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLLinkElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,101 @@
+"use strict";
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const idlUtils = require("../generated/utils");
+const { fetchStylesheet } = require("../helpers/stylesheets");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const whatwgURL = require("whatwg-url");
+
+// Important reading: "appropriate times to obtain the resource" in
+// https://html.spec.whatwg.org/multipage/semantics.html#link-type-stylesheet
+
+class HTMLLinkElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this.sheet = null;
+  }
+
+  get relList() {
+    if (this._relList === undefined) {
+      this._relList = DOMTokenList.createImpl(this._globalObject, [], {
+        element: this,
+        attributeLocalName: "rel",
+        supportedTokens: new Set(["stylesheet"])
+      });
+    }
+    return this._relList;
+  }
+
+  _attach() {
+    super._attach();
+    maybeFetchAndProcess(this);
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    if (name === "href") { // TODO crossorigin="" or type=""
+      maybeFetchAndProcess(this);
+    }
+
+    if (name === "rel" && this._relList !== undefined) {
+      this._relList.attrModified();
+    }
+  }
+
+  get _accept() {
+    return "text/css,*/*;q=0.1";
+  }
+}
+
+module.exports = {
+  implementation: HTMLLinkElementImpl
+};
+
+// https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet
+function maybeFetchAndProcess(el) {
+  if (!isExternalResourceLink(el)) {
+    return;
+  }
+
+  // Browsing-context connected
+  if (!el.isConnected || !el._ownerDocument._defaultView) {
+    return;
+  }
+
+  fetchAndProcess(el);
+}
+
+// https://html.spec.whatwg.org/multipage/semantics.html#default-fetch-and-process-the-linked-resource
+// TODO: refactor into general link-fetching like the spec.
+function fetchAndProcess(el) {
+  const href = el.getAttributeNS(null, "href");
+
+  if (href === null || href === "") {
+    return;
+  }
+
+  const url = parseURLToResultingURLRecord(href, el._ownerDocument);
+  if (url === null) {
+    return;
+  }
+
+  // TODO handle crossorigin="", nonce, integrity="", referrerpolicy=""
+
+  const serialized = whatwgURL.serializeURL(url);
+
+  fetchStylesheet(el, serialized);
+}
+
+function isExternalResourceLink(el) {
+  // for our purposes, only stylesheets can be external resource links
+  const wrapper = idlUtils.wrapperForImpl(el);
+  if (!/(?:[ \t\n\r\f]|^)stylesheet(?:[ \t\n\r\f]|$)/i.test(wrapper.rel)) {
+    // rel is a space-separated list of tokens, and the original rel types
+    // are case-insensitive.
+    return false;
+  }
+
+  return el.hasAttributeNS(null, "href");
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMapElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMapElementImpl extends HTMLElementImpl {
+  get areas() {
+    return this.getElementsByTagName("AREA");
+  }
+}
+
+module.exports = {
+  implementation: HTMLMapElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMarqueeElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMarqueeElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLMarqueeElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMediaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,138 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const notImplemented = require("../../browser/not-implemented");
+const { fireAnEvent } = require("../helpers/events");
+
+function getTimeRangeDummy() {
+  return {
+    length: 0,
+    start() {
+      return 0;
+    },
+    end() {
+      return 0;
+    }
+  };
+}
+
+class HTMLMediaElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._muted = false;
+    this._volume = 1.0;
+    this.readyState = 0;
+    this.networkState = 0;
+    this.currentTime = 0;
+    this.currentSrc = "";
+    this.buffered = getTimeRangeDummy();
+    this.seeking = false;
+    this.duration = NaN;
+    this.paused = true;
+    this.played = getTimeRangeDummy();
+    this.seekable = getTimeRangeDummy();
+    this.ended = false;
+    this.audioTracks = [];
+    this.videoTracks = [];
+    this.textTracks = [];
+  }
+
+  get defaultPlaybackRate() {
+    if (this._defaultPlaybackRate === undefined) {
+      return 1.0;
+    }
+    return this._defaultPlaybackRate;
+  }
+
+  set defaultPlaybackRate(v) {
+    if (v === 0.0) {
+      throw DOMException.create(this._globalObject, ["The operation is not supported.", "NotSupportedError"]);
+    }
+    if (this._defaultPlaybackRate !== v) {
+      this._defaultPlaybackRate = v;
+      this._dispatchRateChange();
+    }
+  }
+
+  get playbackRate() {
+    if (this._playbackRate === undefined) {
+      return 1.0;
+    }
+    return this._playbackRate;
+  }
+
+  set playbackRate(v) {
+    if (v !== this._playbackRate) {
+      this._playbackRate = v;
+      this._dispatchRateChange();
+    }
+  }
+
+  get muted() {
+    return this._muted;
+  }
+
+  set muted(v) {
+    if (v !== this._muted) {
+      this._muted = v;
+      this._dispatchVolumeChange();
+    }
+  }
+
+  get defaultMuted() {
+    return this.getAttributeNS(null, "muted") !== null;
+  }
+
+  set defaultMuted(v) {
+    if (v) {
+      this.setAttributeNS(null, "muted", v);
+    } else {
+      this.removeAttributeNS(null, "muted");
+    }
+  }
+
+  get volume() {
+    return this._volume;
+  }
+
+  set volume(v) {
+    if (v < 0 || v > 1) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    if (this._volume !== v) {
+      this._volume = v;
+      this._dispatchVolumeChange();
+    }
+  }
+
+  // Not (yet) implemented according to spec
+  // Should return sane default values
+  load() {
+    notImplemented("HTMLMediaElement.prototype.load", this._ownerDocument._defaultView);
+  }
+  canPlayType() {
+    return "";
+  }
+  play() {
+    notImplemented("HTMLMediaElement.prototype.play", this._ownerDocument._defaultView);
+  }
+  pause() {
+    notImplemented("HTMLMediaElement.prototype.pause", this._ownerDocument._defaultView);
+  }
+  addTextTrack() {
+    notImplemented("HTMLMediaElement.prototype.addTextTrack", this._ownerDocument._defaultView);
+  }
+
+  _dispatchRateChange() {
+    fireAnEvent("ratechange", this);
+  }
+
+  _dispatchVolumeChange() {
+    fireAnEvent("volumechange", this);
+  }
+}
+
+module.exports = {
+  implementation: HTMLMediaElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMenuElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMenuElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLMenuElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMetaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLMetaElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLMetaElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLMeterElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,180 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { parseFloatingPointNumber } = require("../helpers/strings");
+const { getLabelsForLabelable } = require("../helpers/form-controls");
+
+class HTMLMeterElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._labels = null;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-minimum
+  get _minimumValue() {
+    const min = this.getAttributeNS(null, "min");
+    if (min !== null) {
+      const parsed = parseFloatingPointNumber(min);
+      if (parsed !== null) {
+        return parsed;
+      }
+    }
+    return 0;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-maximum
+  get _maximumValue() {
+    let candidate = 1.0;
+
+    const max = this.getAttributeNS(null, "max");
+    if (max !== null) {
+      const parsed = parseFloatingPointNumber(max);
+      if (parsed !== null) {
+        candidate = parsed;
+      }
+    }
+
+    const minimumValue = this._minimumValue;
+    return candidate >= minimumValue ? candidate : minimumValue;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-actual
+  get _actualValue() {
+    let candidate = 0;
+
+    const value = this.getAttributeNS(null, "value");
+    if (value !== null) {
+      const parsed = parseFloatingPointNumber(value);
+      if (parsed !== null) {
+        candidate = parsed;
+      }
+    }
+
+    const minimumValue = this._minimumValue;
+    if (candidate < minimumValue) {
+      return minimumValue;
+    }
+
+    const maximumValue = this._maximumValue;
+    return candidate > maximumValue ? maximumValue : candidate;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-low
+  get _lowBoundary() {
+    const minimumValue = this._minimumValue;
+    let candidate = minimumValue;
+
+    const low = this.getAttributeNS(null, "low");
+    if (low !== null) {
+      const parsed = parseFloatingPointNumber(low);
+      if (parsed !== null) {
+        candidate = parsed;
+      }
+    }
+
+    if (candidate < minimumValue) {
+      return minimumValue;
+    }
+
+    const maximumValue = this._maximumValue;
+    return candidate > maximumValue ? maximumValue : candidate;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-high
+  get _highBoundary() {
+    const maximumValue = this._maximumValue;
+    let candidate = maximumValue;
+
+    const high = this.getAttributeNS(null, "high");
+    if (high !== null) {
+      const parsed = parseFloatingPointNumber(high);
+      if (parsed !== null) {
+        candidate = parsed;
+      }
+    }
+
+    const lowBoundary = this._lowBoundary;
+    if (candidate < lowBoundary) {
+      return lowBoundary;
+    }
+
+    return candidate > maximumValue ? maximumValue : candidate;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-meter-optimum
+  get _optimumPoint() {
+    const minimumValue = this._minimumValue;
+    const maximumValue = this._maximumValue;
+    let candidate = (minimumValue + maximumValue) / 2;
+
+    const optimum = this.getAttributeNS(null, "optimum");
+    if (optimum !== null) {
+      const parsed = parseFloatingPointNumber(optimum);
+      if (parsed !== null) {
+        candidate = parsed;
+      }
+    }
+
+    if (candidate < minimumValue) {
+      return minimumValue;
+    }
+
+    return candidate > maximumValue ? maximumValue : candidate;
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+
+  get value() {
+    return this._actualValue;
+  }
+
+  set value(val) {
+    this.setAttributeNS(null, "value", String(val));
+  }
+
+  get min() {
+    return this._minimumValue;
+  }
+
+  set min(val) {
+    this.setAttributeNS(null, "min", String(val));
+  }
+
+  get max() {
+    return this._maximumValue;
+  }
+
+  set max(val) {
+    this.setAttributeNS(null, "max", String(val));
+  }
+
+  get low() {
+    return this._lowBoundary;
+  }
+
+  set low(val) {
+    this.setAttributeNS(null, "low", String(val));
+  }
+
+  get high() {
+    return this._highBoundary;
+  }
+
+  set high(val) {
+    this.setAttributeNS(null, "high", String(val));
+  }
+
+  get optimum() {
+    return this._optimumPoint;
+  }
+
+  set optimum(val) {
+    this.setAttributeNS(null, "optimum", String(val));
+  }
+}
+
+module.exports = {
+  implementation: HTMLMeterElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLModElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLModElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+  implementation: HTMLModElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLOListElementImpl extends HTMLElementImpl {
+  get start() {
+    const value = parseInt(this.getAttributeNS(null, "start"));
+
+    if (!isNaN(value)) {
+      return value;
+    }
+
+    return 1;
+  }
+  set start(value) {
+    this.setAttributeNS(null, "start", value);
+  }
+}
+
+module.exports = {
+  implementation: HTMLOListElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLObjectElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,26 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const { formOwner } = require("../helpers/form-controls");
+
+class HTMLObjectElementImpl extends HTMLElementImpl {
+  get form() {
+    return formOwner(this);
+  }
+
+  get contentDocument() {
+    return null;
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    return true;
+  }
+}
+
+mixin(HTMLObjectElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLObjectElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptGroupElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLOptGroupElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLOptGroupElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,146 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const NODE_TYPE = require("../node-type");
+const { stripAndCollapseASCIIWhitespace } = require("../helpers/strings");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const { closest } = require("../helpers/traversal");
+const { formOwner } = require("../helpers/form-controls");
+
+class HTMLOptionElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    // whenever selectedness is set to true, make sure all
+    // other options set selectedness to false
+    this._selectedness = false;
+    this._dirtyness = false;
+  }
+
+  _removeOtherSelectedness() {
+    // Remove the selectedness flag from all other options in this select
+    const select = this._selectNode;
+
+    if (select && !select.hasAttributeNS(null, "multiple")) {
+      for (const option of select.options) {
+        if (option !== this) {
+          option._selectedness = false;
+        }
+      }
+    }
+  }
+
+  _askForAReset() {
+    const select = this._selectNode;
+    if (select) {
+      select._askedForAReset();
+    }
+  }
+
+  _attrModified(name, value, oldValue) {
+    if (!this._dirtyness && name === "selected") {
+      this._selectedness = this.hasAttributeNS(null, "selected");
+      if (this._selectedness) {
+        this._removeOtherSelectedness();
+      }
+      this._askForAReset();
+    }
+    super._attrModified(name, value, oldValue);
+  }
+
+  get _selectNode() {
+    let select = domSymbolTree.parent(this);
+    if (!select) {
+      return null;
+    }
+
+    if (select.nodeName.toUpperCase() !== "SELECT") {
+      select = domSymbolTree.parent(select);
+      if (!select || select.nodeName.toUpperCase() !== "SELECT") {
+        return null;
+      }
+    }
+    return select;
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get text() {
+    return stripAndCollapseASCIIWhitespace(childTextContentExcludingDescendantsOfScript(this));
+  }
+  set text(value) {
+    this.textContent = value;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-option-value
+  _getValue() {
+    if (this.hasAttributeNS(null, "value")) {
+      return this.getAttributeNS(null, "value");
+    }
+
+    return this.text;
+  }
+
+  get value() {
+    return this._getValue();
+  }
+  set value(value) {
+    this.setAttributeNS(null, "value", value);
+  }
+
+  get index() {
+    const select = closest(this, "select");
+    if (select === null) {
+      return 0;
+    }
+
+    return select.options.indexOf(this);
+  }
+
+  get selected() {
+    return this._selectedness;
+  }
+  set selected(s) {
+    this._dirtyness = true;
+    this._selectedness = Boolean(s);
+    if (this._selectedness) {
+      this._removeOtherSelectedness();
+    }
+    this._askForAReset();
+    this._modified();
+  }
+
+  get label() {
+    if (this.hasAttributeNS(null, "label")) {
+      return this.getAttributeNS(null, "label");
+    }
+
+    return this.text;
+  }
+  set label(value) {
+    this.setAttributeNS(null, "label", value);
+  }
+}
+
+function childTextContentExcludingDescendantsOfScript(root) {
+  let text = "";
+  for (const child of domSymbolTree.childrenIterator(root)) {
+    if (child._localName === "script" && (child._namespaceURI === HTML_NS || child._namespaceURI === SVG_NS)) {
+      continue;
+    }
+
+    if (child.nodeType === NODE_TYPE.TEXT_NODE || child.nodeType === NODE_TYPE.CDATA_SECTION_NODE) {
+      text += child.nodeValue;
+    } else {
+      text += childTextContentExcludingDescendantsOfScript(child);
+    }
+  }
+  return text;
+}
+
+module.exports = {
+  implementation: HTMLOptionElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOptionsCollection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,110 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_CONTAINED_BY } = require("../node-document-position");
+const Element = require("../generated/Element");
+const Node = require("../generated/Node");
+const HTMLCollectionImpl = require("./HTMLCollection-impl").implementation;
+
+exports.implementation = class HTMLOptionsCollectionImpl extends HTMLCollectionImpl {
+  // inherits supported property indices
+  get length() {
+    this._update();
+    return this._list.length;
+  }
+  set length(value) {
+    this._update();
+    if (value > this._list.length) {
+      const doc = this._element._ownerDocument;
+      for (let i = this._list.length; i < value; i++) {
+        const el = doc.createElement("option");
+        this._element.appendChild(el);
+      }
+    } else if (value < this._list.length) {
+      for (let i = this._list.length - 1; i >= value; i--) {
+        const el = this._list[i];
+        this._element.removeChild(el);
+      }
+    }
+  }
+
+  get [idlUtils.supportedPropertyNames]() {
+    this._update();
+    const result = new Set();
+    for (const element of this._list) {
+      result.add(element.getAttributeNS(null, "id"));
+      result.add(element.getAttributeNS(null, "name"));
+    }
+    return result;
+  }
+  [idlUtils.indexedSetNew](index, value) {
+    if (value === null) {
+      this.remove(index);
+      return;
+    }
+    this._update();
+    const { length } = this._list;
+    const n = index - length;
+    if (n > 0) {
+      const doc = this._element._ownerDocument;
+      const frag = doc.createDocumentFragment();
+      // Spec says n - 1, but n seems to be the right number here.
+      for (let i = 0; i < n; i++) {
+        const el = doc.createElement("option");
+        frag.appendChild(el);
+      }
+      this._element._append(frag);
+    }
+    if (n >= 0) {
+      this._element._append(value);
+    } else {
+      this._element._replace(value, this._list[index]);
+    }
+  }
+  [idlUtils.indexedSetExisting](index, value) {
+    return this[idlUtils.indexedSetNew](index, value);
+  }
+  add(element, before) {
+    if (this._element.compareDocumentPosition(element) & DOCUMENT_POSITION_CONTAINS) {
+      throw DOMException.create(this._globalObject, [
+        "The operation would yield an incorrect node tree.",
+        "HierarchyRequestError"
+      ]);
+    }
+    if (Element.isImpl(before) && !(this._element.compareDocumentPosition(before) & DOCUMENT_POSITION_CONTAINED_BY)) {
+      throw DOMException.create(this._globalObject, ["The object can not be found here.", "NotFoundError"]);
+    }
+    if (element === before) {
+      return;
+    }
+
+    let reference = null;
+    if (Node.isImpl(before)) {
+      reference = before;
+    } else if (typeof before === "number") {
+      this._update();
+      reference = this._list[before] || null;
+    }
+
+    const parent = reference !== null ? reference.parentNode : this._element;
+    parent._preInsert(element, reference);
+  }
+  remove(index) {
+    this._update();
+    if (this._list.length === 0) {
+      return;
+    }
+    if (index < 0 || index >= this._list.length) {
+      return;
+    }
+    const element = this._list[index];
+    element.parentNode._remove(element);
+  }
+  get selectedIndex() {
+    return this._element.selectedIndex;
+  }
+  set selectedIndex(value) {
+    this._element.selectedIndex = value;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOrSVGElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,85 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+const { isSummaryForParentDetails } = require("../helpers/details");
+const focusing = require("../helpers/focusing");
+const { HTML_NS, SVG_NS } = require("../helpers/namespaces");
+const DOMStringMap = require("../generated/DOMStringMap");
+
+const tabIndexReflectAllowedHTMLElements = new Set([
+  "a", "area", "button", "frame", "iframe",
+  "input", "object", "select", "textarea"
+]);
+
+class HTMLOrSVGElementImpl {
+  _initHTMLOrSVGElement() {
+    this._tabIndex = 0;
+    this._dataset = DOMStringMap.createImpl(this._globalObject, [], { element: this });
+  }
+
+  get dataset() {
+    return this._dataset;
+  }
+
+  // TODO this should be [Reflect]able if we added default value support to webidl2js's [Reflect]
+  get tabIndex() {
+    if (!this.hasAttributeNS(null, "tabindex")) {
+      if ((this.namespaceURI === HTML_NS && (tabIndexReflectAllowedHTMLElements.has(this._localName) ||
+                                             (this._localName === "summary" && isSummaryForParentDetails(this)))) ||
+          (this.namespaceURI === SVG_NS && this._localName === "a")) {
+        return 0;
+      }
+      return -1;
+    }
+    return conversions.long(this.getAttributeNS(null, "tabindex"));
+  }
+
+  set tabIndex(value) {
+    this.setAttributeNS(null, "tabindex", String(value));
+  }
+
+  focus() {
+    if (!focusing.isFocusableAreaElement(this)) {
+      return;
+    }
+    const ownerDocument = this._ownerDocument;
+    const previous = ownerDocument._lastFocusedElement;
+
+    if (previous === this) {
+      return;
+    }
+
+    ownerDocument._lastFocusedElement = null;
+    if (previous) {
+      focusing.fireFocusEventWithTargetAdjustment("blur", previous, this);
+      focusing.fireFocusEventWithTargetAdjustment("focusout", previous, this, { bubbles: true });
+    } else {
+      const frameElement = ownerDocument._defaultView._frameElement;
+      if (frameElement) {
+        const frameLastFocusedElement = frameElement.ownerDocument._lastFocusedElement;
+        frameElement.ownerDocument._lastFocusedElement = null;
+        focusing.fireFocusEventWithTargetAdjustment("blur", frameLastFocusedElement, null);
+        focusing.fireFocusEventWithTargetAdjustment("focusout", frameLastFocusedElement, null, { bubbles: true });
+        frameElement.ownerDocument._lastFocusedElement = frameElement;
+      }
+    }
+
+    ownerDocument._lastFocusedElement = this;
+    focusing.fireFocusEventWithTargetAdjustment("focus", this, previous);
+    focusing.fireFocusEventWithTargetAdjustment("focusin", this, previous, { bubbles: true });
+  }
+
+  blur() {
+    if (this._ownerDocument._lastFocusedElement !== this || !focusing.isFocusableAreaElement(this)) {
+      return;
+    }
+
+    this._ownerDocument._lastFocusedElement = null;
+    focusing.fireFocusEventWithTargetAdjustment("blur", this, this._ownerDocument);
+    focusing.fireFocusEventWithTargetAdjustment("focusout", this, this._ownerDocument, { bubbles: true });
+    focusing.fireFocusEventWithTargetAdjustment("focus", this._ownerDocument, this);
+    focusing.fireFocusEventWithTargetAdjustment("focusin", this._ownerDocument, this, { bubbles: true });
+  }
+}
+
+exports.implementation = HTMLOrSVGElementImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLOutputElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+"use strict";
+
+const DOMTokenList = require("../generated/DOMTokenList");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const { getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+
+class HTMLOutputElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._labels = null;
+    this._defaultValueOverride = null;
+
+    this._customValidityErrorMessage = "";
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    if (name === "for" && this._htmlFor !== undefined) {
+      this._htmlFor.attrModified();
+    }
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    return true;
+  }
+
+  _formReset() {
+    this.textContent = this.defaultValue;
+    this._defaultValueOverride = null;
+  }
+
+  get htmlFor() {
+    if (this._htmlFor === undefined) {
+      this._htmlFor = DOMTokenList.createImpl(this._globalObject, [], {
+        element: this,
+        attributeLocalName: "for"
+      });
+    }
+    return this._htmlFor;
+  }
+
+  get type() {
+    return "output";
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get value() {
+    return this.textContent;
+  }
+
+  set value(val) {
+    this._defaultValueOverride = this.defaultValue;
+    this.textContent = val;
+  }
+
+  get defaultValue() {
+    if (this._defaultValueOverride !== null) {
+      return this._defaultValueOverride;
+    }
+    return this.textContent;
+  }
+
+  set defaultValue(val) {
+    if (this._defaultValueOverride === null) {
+      this.textContent = val;
+      return;
+    }
+
+    this._defaultValueOverride = val;
+  }
+}
+
+mixin(HTMLOutputElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLOutputElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParagraphElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLParagraphElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLParagraphElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLParamElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLParamElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLParamElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPictureElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLPictureElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLPictureElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLPreElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLPreElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLPreElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLProgressElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,74 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { getLabelsForLabelable } = require("../helpers/form-controls");
+const { parseFloatingPointNumber } = require("../helpers/strings");
+
+class HTMLProgressElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._labels = null;
+  }
+
+  get _isDeterminate() {
+    return this.hasAttributeNS(null, "value");
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-progress-value
+  get _value() {
+    const valueAttr = this.getAttributeNS(null, "value");
+    const parsedValue = parseFloatingPointNumber(valueAttr);
+    if (parsedValue !== null && parsedValue > 0) {
+      return parsedValue;
+    }
+    return 0;
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#concept-progress-current-value
+  get _currentValue() {
+    const value = this._value;
+    return value > this.max ? this.max : value;
+  }
+
+  get value() {
+    if (this._isDeterminate) {
+      return this._currentValue;
+    }
+    return 0;
+  }
+  set value(value) {
+    this.setAttributeNS(null, "value", value);
+  }
+
+  get max() {
+    const max = this.getAttributeNS(null, "max");
+    if (max !== null) {
+      const parsedMax = parseFloatingPointNumber(max);
+      if (parsedMax !== null && parsedMax > 0) {
+        return parsedMax;
+      }
+    }
+    return 1.0;
+  }
+  set max(value) {
+    if (value > 0) {
+      this.setAttributeNS(null, "max", value);
+    }
+  }
+
+  get position() {
+    if (!this._isDeterminate) {
+      return -1;
+    }
+
+    return this._currentValue / this.max;
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+}
+
+module.exports = {
+  implementation: HTMLProgressElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLQuoteElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLQuoteElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+  implementation: HTMLQuoteElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLScriptElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,265 @@
+"use strict";
+const vm = require("vm");
+const whatwgEncoding = require("whatwg-encoding");
+const MIMEType = require("whatwg-mimetype");
+const { serializeURL } = require("whatwg-url");
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const reportException = require("../helpers/runtime-script-errors");
+const { domSymbolTree, cloningSteps } = require("../helpers/internal-constants");
+const { asciiLowercase } = require("../helpers/strings");
+const { childTextContent } = require("../helpers/text");
+const { fireAnEvent } = require("../helpers/events");
+const { parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const nodeTypes = require("../node-type");
+
+const jsMIMETypes = new Set([
+  "application/ecmascript",
+  "application/javascript",
+  "application/x-ecmascript",
+  "application/x-javascript",
+  "text/ecmascript",
+  "text/javascript",
+  "text/javascript1.0",
+  "text/javascript1.1",
+  "text/javascript1.2",
+  "text/javascript1.3",
+  "text/javascript1.4",
+  "text/javascript1.5",
+  "text/jscript",
+  "text/livescript",
+  "text/x-ecmascript",
+  "text/x-javascript"
+]);
+
+class HTMLScriptElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._alreadyStarted = false;
+    this._parserInserted = false; // set by the parser
+  }
+
+  _attach() {
+    super._attach();
+
+
+    // In our current terribly-hacky document.write() implementation, we parse in a div them move elements into the main
+    // document. Thus _eval() will bail early when it gets in _poppedOffStackOfOpenElements(), since we're not attached
+    // then. Instead, we'll let it eval here.
+    if (!this._parserInserted || this._isMovingDueToDocumentWrite) {
+      this._eval();
+    }
+  }
+
+  _canRunScript() {
+    const document = this._ownerDocument;
+    // Equivalent to the spec's "scripting is disabled" check.
+    if (!document._defaultView || document._defaultView._runScripts !== "dangerously" || document._scriptingDisabled) {
+      return false;
+    }
+
+    return true;
+  }
+
+  _fetchExternalScript() {
+    const document = this._ownerDocument;
+    const resourceLoader = document._resourceLoader;
+    const defaultEncoding = whatwgEncoding.labelToName(this.getAttributeNS(null, "charset")) || document._encoding;
+    let request;
+
+    if (!this._canRunScript()) {
+      return;
+    }
+
+    const src = this.getAttributeNS(null, "src");
+    const url = parseURLToResultingURLRecord(src, this._ownerDocument);
+    if (url === null) {
+      return;
+    }
+    const urlString = serializeURL(url);
+
+    const onLoadExternalScript = data => {
+      const { response } = request;
+      let contentType;
+
+      if (response && response.statusCode !== undefined && response.statusCode >= 400) {
+        throw new Error("Status code: " + response.statusCode);
+      }
+
+      if (response) {
+        contentType = MIMEType.parse(response.headers["content-type"]) || new MIMEType("text/plain");
+      }
+
+      const encoding = whatwgEncoding.getBOMEncoding(data) ||
+        (contentType && whatwgEncoding.labelToName(contentType.parameters.get("charset"))) ||
+        defaultEncoding;
+      const script = whatwgEncoding.decode(data, encoding);
+
+      this._innerEval(script, urlString);
+    };
+
+    request = resourceLoader.fetch(urlString, {
+      element: this,
+      onLoad: onLoadExternalScript
+    });
+  }
+
+  _fetchInternalScript() {
+    const document = this._ownerDocument;
+
+    if (!this._canRunScript()) {
+      return;
+    }
+
+    document._queue.push(null, () => {
+      this._innerEval(this.text, document.URL);
+
+      fireAnEvent("load", this);
+    }, null, false, this);
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    if (this._attached && !this._startedEval && name === "src" && oldValue === null && value !== null) {
+      this._fetchExternalScript();
+    }
+  }
+
+  _poppedOffStackOfOpenElements() {
+    // This seems to roughly correspond to
+    // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-incdata:prepare-a-script, although we certainly
+    // don't implement the full semantics.
+    this._eval();
+  }
+
+  // Vaguely similar to https://html.spec.whatwg.org/multipage/scripting.html#prepare-a-script, but we have a long way
+  // to go before it's aligned.
+  _eval() {
+    if (this._alreadyStarted) {
+      return;
+    }
+
+    // TODO: this text check doesn't seem completely the same as the spec, which e.g. will try to execute scripts with
+    // child element nodes. Spec bug? https://github.com/whatwg/html/issues/3419
+    if (!this.hasAttributeNS(null, "src") && this.text.length === 0) {
+      return;
+    }
+
+    if (!this._attached) {
+      return;
+    }
+
+    const scriptBlocksTypeString = this._getTypeString();
+    const type = getType(scriptBlocksTypeString);
+
+    if (type !== "classic") {
+      // TODO: implement modules, and then change the check to `type === null`.
+      return;
+    }
+
+    this._alreadyStarted = true;
+
+    // TODO: implement nomodule here, **but only after we support modules**.
+
+    // At this point we completely depart from the spec.
+
+    if (this.hasAttributeNS(null, "src")) {
+      this._fetchExternalScript();
+    } else {
+      this._fetchInternalScript();
+    }
+  }
+
+  _innerEval(text, filename) {
+    this._ownerDocument._writeAfterElement = this;
+    processJavaScript(this, text, filename);
+    delete this._ownerDocument._writeAfterElement;
+  }
+
+  _getTypeString() {
+    const typeAttr = this.getAttributeNS(null, "type");
+    const langAttr = this.getAttributeNS(null, "language");
+
+    if (typeAttr === "") {
+      return "text/javascript";
+    }
+
+    if (typeAttr === null && langAttr === "") {
+      return "text/javascript";
+    }
+
+    if (typeAttr === null && langAttr === null) {
+      return "text/javascript";
+    }
+
+    if (typeAttr !== null) {
+      return typeAttr.trim();
+    }
+
+    if (langAttr !== null) {
+      return "text/" + langAttr;
+    }
+
+    return null;
+  }
+
+  get text() {
+    return childTextContent(this);
+  }
+
+  set text(text) {
+    this.textContent = text;
+  }
+
+  // https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
+  [cloningSteps](copy, node) {
+    copy._alreadyStarted = node._alreadyStarted;
+  }
+}
+
+function processJavaScript(element, code, filename) {
+  const document = element.ownerDocument;
+  const window = document && document._global;
+
+  if (window) {
+    document._currentScript = element;
+
+    let lineOffset = 0;
+    if (!element.hasAttributeNS(null, "src")) {
+      for (const child of domSymbolTree.childrenIterator(element)) {
+        if (child.nodeType === nodeTypes.TEXT_NODE) {
+          if (child.sourceCodeLocation) {
+            lineOffset = child.sourceCodeLocation.startLine - 1;
+          }
+          break;
+        }
+      }
+    }
+
+    try {
+      vm.runInContext(code, window, { filename, lineOffset, displayErrors: false });
+    } catch (e) {
+      reportException(window, e, filename);
+    } finally {
+      document._currentScript = null;
+    }
+  }
+}
+
+function getType(typeString) {
+  const lowercased = asciiLowercase(typeString);
+  // Cannot use whatwg-mimetype parsing because that strips whitespace. The spec demands a strict string comparison.
+  // That is, the type="" attribute is not really related to MIME types at all.
+  if (jsMIMETypes.has(lowercased)) {
+    return "classic";
+  }
+  if (lowercased === "module") {
+    return "module";
+  }
+  return null;
+}
+
+module.exports = {
+  implementation: HTMLScriptElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSelectElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,283 @@
+"use strict";
+
+const conversions = require("webidl-conversions");
+
+const idlUtils = require("../generated/utils.js");
+const ValidityState = require("../generated/ValidityState");
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const { mixin } = require("../../utils");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const NODE_TYPE = require("../node-type");
+const HTMLCollection = require("../generated/HTMLCollection");
+const HTMLOptionsCollection = require("../generated/HTMLOptionsCollection");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { getLabelsForLabelable, formOwner, isDisabled } = require("../helpers/form-controls");
+const { parseNonNegativeInteger } = require("../helpers/strings");
+
+class HTMLSelectElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._options = HTMLOptionsCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => {
+        // Customized domSymbolTree.treeToArray() clone.
+        const array = [];
+        for (const child of domSymbolTree.childrenIterator(this)) {
+          if (child._localName === "option") {
+            array.push(child);
+          } else if (child._localName === "optgroup") {
+            for (const childOfGroup of domSymbolTree.childrenIterator(child)) {
+              if (childOfGroup._localName === "option") {
+                array.push(childOfGroup);
+              }
+            }
+          }
+        }
+        return array;
+      }
+    });
+    this._selectedOptions = null; // lazy
+
+    this._customValidityErrorMessage = "";
+
+    this._labels = null;
+  }
+
+  _formReset() {
+    for (const option of this.options) {
+      option._selectedness = option.hasAttributeNS(null, "selected");
+      option._dirtyness = false;
+    }
+    this._askedForAReset();
+  }
+
+  _askedForAReset() {
+    if (this.hasAttributeNS(null, "multiple")) {
+      return;
+    }
+
+    const selected = this.options.filter(opt => opt._selectedness);
+
+    const size = this._displaySize;
+    if (size === 1 && !selected.length) {
+      // select the first option that is not disabled
+      for (const option of this.options) {
+        let disabled = option.hasAttributeNS(null, "disabled");
+        const parentNode = domSymbolTree.parent(option);
+        if (parentNode &&
+          parentNode.nodeName.toUpperCase() === "OPTGROUP" &&
+          parentNode.hasAttributeNS(null, "disabled")) {
+          disabled = true;
+        }
+
+        if (!disabled) {
+          // (do not set dirty)
+          option._selectedness = true;
+          break;
+        }
+      }
+    } else if (selected.length >= 2) {
+      // select the last selected option
+      selected.forEach((option, index) => {
+        option._selectedness = index === selected.length - 1;
+      });
+    }
+  }
+
+  _descendantAdded(parent, child) {
+    if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+      this._askedForAReset();
+    }
+
+    super._descendantAdded(parent, child);
+  }
+
+  _descendantRemoved(parent, child) {
+    if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+      this._askedForAReset();
+    }
+
+    super._descendantRemoved(parent, child);
+  }
+
+  _attrModified(name, value, oldValue) {
+    if (name === "multiple" || name === "size") {
+      this._askedForAReset();
+    }
+    super._attrModified(name, value, oldValue);
+  }
+
+  get _displaySize() {
+    if (this.hasAttributeNS(null, "size")) {
+      const size = parseNonNegativeInteger(this.getAttributeNS(null, "size"));
+      if (size !== null) {
+        return size;
+      }
+    }
+    return this.hasAttributeNS(null, "multiple") ? 4 : 1;
+  }
+
+  get _mutable() {
+    return !isDisabled(this);
+  }
+
+  get options() {
+    return this._options;
+  }
+
+  get selectedOptions() {
+    return HTMLCollection.createImpl(this._globalObject, [], {
+      element: this,
+      query: () => domSymbolTree.treeToArray(this, {
+        filter: node => node._localName === "option" && node._selectedness === true
+      })
+    });
+  }
+
+  get selectedIndex() {
+    for (let i = 0; i < this.options.length; i++) {
+      if (this.options.item(i)._selectedness) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+  set selectedIndex(index) {
+    for (let i = 0; i < this.options.length; i++) {
+      this.options.item(i)._selectedness = false;
+    }
+
+    const selectedOption = this.options.item(index);
+    if (selectedOption) {
+      selectedOption._selectedness = true;
+      selectedOption._dirtyness = true;
+    }
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+
+  get value() {
+    for (const option of this.options) {
+      if (option._selectedness) {
+        return option.value;
+      }
+    }
+
+    return "";
+  }
+
+  set value(val) {
+    for (const option of this.options) {
+      if (option.value === val) {
+        option._selectedness = true;
+        option._dirtyness = true;
+      } else {
+        option._selectedness = false;
+      }
+
+      option._modified();
+    }
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get type() {
+    return this.hasAttributeNS(null, "multiple") ? "select-multiple" : "select-one";
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    return this.options[idlUtils.supportedPropertyIndices];
+  }
+
+  get length() {
+    return this.options.length;
+  }
+
+  set length(value) {
+    this.options.length = value;
+  }
+
+  item(index) {
+    return this.options.item(index);
+  }
+
+  namedItem(name) {
+    return this.options.namedItem(name);
+  }
+
+  [idlUtils.indexedSetNew](index, value) {
+    return this.options[idlUtils.indexedSetNew](index, value);
+  }
+
+  [idlUtils.indexedSetExisting](index, value) {
+    return this.options[idlUtils.indexedSetExisting](index, value);
+  }
+
+  add(opt, before) {
+    this.options.add(opt, before);
+  }
+
+  remove(index) {
+    if (arguments.length > 0) {
+      index = conversions.long(index, {
+        context: "Failed to execute 'remove' on 'HTMLSelectElement': parameter 1"
+      });
+      this.options.remove(index);
+    } else {
+      super.remove();
+    }
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    return this.hasAttributeNS(null, "readonly");
+  }
+
+  // Constraint validation: If the element has its required attribute specified,
+  // and either none of the option elements in the select element's list of options
+  // have their selectedness set to true, or the only option element in the select
+  // element's list of options with its selectedness set to true is the placeholder
+  // label option, then the element is suffering from being missing.
+  get validity() {
+    if (!this._validity) {
+      const state = {
+        valueMissing: () => {
+          if (!this.hasAttributeNS(null, "required")) {
+            return false;
+          }
+          const selectedOptionIndex = this.selectedIndex;
+          return selectedOptionIndex < 0 || (selectedOptionIndex === 0 && this._hasPlaceholderOption);
+        }
+      };
+
+      this._validity = ValidityState.createImpl(this._globalObject, [], {
+        element: this,
+        state
+      });
+    }
+    return this._validity;
+  }
+
+  // If a select element has a required attribute specified, does not have a multiple attribute
+  // specified, and has a display size of 1; and if the value of the first option element in the
+  // select element's list of options (if any) is the empty string, and that option element's parent
+  // node is the select element(and not an optgroup element), then that option is the select
+  // element's placeholder label option.
+  // https://html.spec.whatwg.org/multipage/form-elements.html#placeholder-label-option
+  get _hasPlaceholderOption() {
+    return this.hasAttributeNS(null, "required") && !this.hasAttributeNS(null, "multiple") &&
+      this._displaySize === 1 && this.options.length > 0 && this.options.item(0).value === "" &&
+      this.options.item(0).parentNode._localName !== "optgroup";
+  }
+}
+
+mixin(HTMLSelectElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLSelectElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSlotElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,59 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const HTMLElement = require("../generated/HTMLElement");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const { nodeRoot } = require("../helpers/node");
+const { assignSlotableForTree, findFlattenedSlotables } = require("../helpers/shadow-dom");
+
+class HTMLSlotElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._assignedNodes = [];
+  }
+
+  // https://dom.spec.whatwg.org/#slot-name
+  get name() {
+    return this.getAttributeNS(null, "name") || "";
+  }
+
+  _attrModified(name, value, oldValue) {
+    super._attrModified(name, value, oldValue);
+
+    // https://dom.spec.whatwg.org/#slot-name
+    if (name === "name") {
+      if (value === oldValue) {
+        return;
+      }
+
+      if (value === null && oldValue === "") {
+        return;
+      }
+
+      if (value === "" && oldValue === null) {
+        return;
+      }
+
+      assignSlotableForTree(nodeRoot(this));
+    }
+  }
+
+  // https://html.spec.whatwg.org/#dom-slot-assignednodes
+  assignedNodes(options) {
+    if (!options || !options.flatten) {
+      return this._assignedNodes.map(idlUtils.wrapperForImpl);
+    }
+
+    return findFlattenedSlotables(this).map(idlUtils.wrapperForImpl);
+  }
+
+  // https://html.spec.whatwg.org/#dom-slot-assignedelements
+  assignedElements(options) {
+    return this.assignedNodes(options).filter(HTMLElement.is);
+  }
+}
+
+module.exports = {
+  implementation: HTMLSlotElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSourceElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,8 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLSourceElementImpl extends HTMLElementImpl {}
+
+module.exports = {
+  implementation: HTMLSourceElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLSpanElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLSpanElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLSpanElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLStyleElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,74 @@
+"use strict";
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { removeStylesheet, createStylesheet } = require("../helpers/stylesheets");
+const { documentBaseURL } = require("../helpers/document-base-url");
+const { childTextContent } = require("../helpers/text");
+const { asciiCaseInsensitiveMatch } = require("../helpers/strings");
+
+class HTMLStyleElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this.sheet = null;
+    this._isOnStackOfOpenElements = false;
+  }
+
+  _attach() {
+    super._attach();
+    if (!this._isOnStackOfOpenElements) {
+      this._updateAStyleBlock();
+    }
+  }
+
+  _detach() {
+    super._detach();
+    if (!this._isOnStackOfOpenElements) {
+      this._updateAStyleBlock();
+    }
+  }
+
+  _childTextContentChangeSteps() {
+    super._childTextContentChangeSteps();
+
+    // This guard is not required by the spec, but should be unobservable (since you can't run script during the middle
+    // of parsing a <style> element) and saves a bunch of unnecessary work.
+    if (!this._isOnStackOfOpenElements) {
+      this._updateAStyleBlock();
+    }
+  }
+
+  _poppedOffStackOfOpenElements() {
+    this._isOnStackOfOpenElements = false;
+    this._updateAStyleBlock();
+  }
+
+  _pushedOnStackOfOpenElements() {
+    this._isOnStackOfOpenElements = true;
+  }
+
+  _updateAStyleBlock() {
+    if (this.sheet) {
+      removeStylesheet(this.sheet, this);
+    }
+
+    // Browsing-context connected, per https://github.com/whatwg/html/issues/4547
+    if (!this.isConnected || !this._ownerDocument._defaultView) {
+      return;
+    }
+
+    const type = this.getAttributeNS(null, "type");
+    if (type !== null && type !== "" && !asciiCaseInsensitiveMatch(type, "text/css")) {
+      return;
+    }
+
+    // Not implemented: CSP
+
+    const content = childTextContent(this);
+    // Not implemented: a bunch of other state, e.g. title/media attributes
+    createStylesheet(content, this, documentBaseURL(this._ownerDocument));
+  }
+}
+
+module.exports = {
+  implementation: HTMLStyleElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCaptionElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTableCaptionElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLTableCaptionElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableCellElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,73 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const { asciiLowercase, parseNonNegativeInteger } = require("../helpers/strings");
+const { closest } = require("../helpers/traversal");
+
+function reflectedAttributeClampedToRange(attrValue, min, max, defaultValue = 0) {
+  if (attrValue === null) {
+    return defaultValue;
+  }
+  const parsed = parseNonNegativeInteger(attrValue);
+  if (parsed === null) {
+    return defaultValue;
+  }
+  if (parsed < min) {
+    return min;
+  }
+  if (parsed > max) {
+    return max;
+  }
+  return parsed;
+}
+
+class HTMLTableCellElementImpl extends HTMLElementImpl {
+  get colSpan() {
+    return reflectedAttributeClampedToRange(this.getAttributeNS(null, "colspan"), 1, 1000, 1);
+  }
+
+  set colSpan(V) {
+    this.setAttributeNS(null, "colspan", String(V));
+  }
+
+  get rowSpan() {
+    return reflectedAttributeClampedToRange(this.getAttributeNS(null, "rowspan"), 0, 65534, 1);
+  }
+
+  set rowSpan(V) {
+    this.setAttributeNS(null, "rowspan", String(V));
+  }
+
+  get cellIndex() {
+    const tr = closest(this, "tr");
+    if (tr === null) {
+      return -1;
+    }
+
+    return tr.cells.indexOf(this);
+  }
+
+  get scope() {
+    let value = this.getAttributeNS(null, "scope");
+    if (value === null) {
+      return "";
+    }
+
+    // Enumerated attribute is matched ASCII-case-insensitively.
+    value = asciiLowercase(value);
+    if (value === "row" || value === "col" || value === "rowgroup" || value === "colgroup") {
+      return value;
+    }
+
+    return "";
+  }
+
+  set scope(V) {
+    this.setAttributeNS(null, "scope", V);
+  }
+}
+
+module.exports = {
+  implementation: HTMLTableCellElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableColElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTableColElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLTableColElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,236 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { HTML_NS } = require("../helpers/namespaces");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { firstChildWithLocalName, childrenByLocalName } = require("../helpers/traversal");
+const HTMLCollection = require("../generated/HTMLCollection");
+const NODE_TYPE = require("../node-type");
+
+function tHeadInsertionPoint(table) {
+  const iterator = domSymbolTree.childrenIterator(table);
+  for (const child of iterator) {
+    if (child.nodeType !== NODE_TYPE.ELEMENT_NODE) {
+      continue;
+    }
+
+    if (child._namespaceURI !== HTML_NS || (child._localName !== "caption" && child._localName !== "colgroup")) {
+      return child;
+    }
+  }
+
+  return null;
+}
+
+class HTMLTableElementImpl extends HTMLElementImpl {
+  get caption() {
+    return firstChildWithLocalName(this, "caption");
+  }
+
+  set caption(value) {
+    const currentCaption = this.caption;
+    if (currentCaption !== null) {
+      this.removeChild(currentCaption);
+    }
+
+    if (value !== null) {
+      const insertionPoint = this.firstChild;
+      this.insertBefore(value, insertionPoint);
+    }
+  }
+
+  get tHead() {
+    return firstChildWithLocalName(this, "thead");
+  }
+
+  set tHead(value) {
+    if (value !== null && value._localName !== "thead") {
+      throw DOMException.create(this._globalObject, [
+        "Cannot set a non-thead element as a table header",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    const currentHead = this.tHead;
+    if (currentHead !== null) {
+      this.removeChild(currentHead);
+    }
+
+    if (value !== null) {
+      const insertionPoint = tHeadInsertionPoint(this);
+      this.insertBefore(value, insertionPoint);
+    }
+  }
+
+  get tFoot() {
+    return firstChildWithLocalName(this, "tfoot");
+  }
+
+  set tFoot(value) {
+    if (value !== null && value._localName !== "tfoot") {
+      throw DOMException.create(this._globalObject, [
+        "Cannot set a non-tfoot element as a table footer",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    const currentFoot = this.tFoot;
+    if (currentFoot !== null) {
+      this.removeChild(currentFoot);
+    }
+
+    if (value !== null) {
+      this.appendChild(value);
+    }
+  }
+
+  get rows() {
+    if (!this._rows) {
+      this._rows = HTMLCollection.createImpl(this._globalObject, [], {
+        element: this,
+        query: () => {
+          const headerRows = [];
+          const bodyRows = [];
+          const footerRows = [];
+
+          const iterator = domSymbolTree.childrenIterator(this);
+          for (const child of iterator) {
+            if (child.nodeType !== NODE_TYPE.ELEMENT_NODE || child._namespaceURI !== HTML_NS) {
+              continue;
+            }
+
+            if (child._localName === "thead") {
+              headerRows.push(...childrenByLocalName(child, "tr"));
+            } else if (child._localName === "tbody") {
+              bodyRows.push(...childrenByLocalName(child, "tr"));
+            } else if (child._localName === "tfoot") {
+              footerRows.push(...childrenByLocalName(child, "tr"));
+            } else if (child._localName === "tr") {
+              bodyRows.push(child);
+            }
+          }
+
+          return [...headerRows, ...bodyRows, ...footerRows];
+        }
+      });
+    }
+    return this._rows;
+  }
+
+  get tBodies() {
+    if (!this._tBodies) {
+      this._tBodies = HTMLCollection.createImpl(this._globalObject, [], {
+        element: this,
+        query: () => childrenByLocalName(this, "tbody")
+      });
+    }
+    return this._tBodies;
+  }
+
+  createTBody() {
+    const el = this._ownerDocument.createElement("TBODY");
+
+    const tbodies = childrenByLocalName(this, "tbody");
+    const insertionPoint = tbodies[tbodies.length - 1];
+
+    if (insertionPoint) {
+      this.insertBefore(el, insertionPoint.nextSibling);
+    } else {
+      this.appendChild(el);
+    }
+    return el;
+  }
+
+  createTHead() {
+    let el = this.tHead;
+    if (!el) {
+      el = this.tHead = this._ownerDocument.createElement("THEAD");
+    }
+    return el;
+  }
+
+  deleteTHead() {
+    this.tHead = null;
+  }
+
+  createTFoot() {
+    let el = this.tFoot;
+    if (!el) {
+      el = this.tFoot = this._ownerDocument.createElement("TFOOT");
+    }
+    return el;
+  }
+
+  deleteTFoot() {
+    this.tFoot = null;
+  }
+
+  createCaption() {
+    let el = this.caption;
+    if (!el) {
+      el = this.caption = this._ownerDocument.createElement("CAPTION");
+    }
+    return el;
+  }
+
+  deleteCaption() {
+    const c = this.caption;
+    if (c) {
+      c.parentNode.removeChild(c);
+    }
+  }
+
+  insertRow(index) {
+    if (index < -1 || index > this.rows.length) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot insert a row at an index that is less than -1 or greater than the number of existing rows",
+        "IndexSizeError"
+      ]);
+    }
+
+    const tr = this._ownerDocument.createElement("tr");
+
+    if (this.rows.length === 0 && this.tBodies.length === 0) {
+      const tBody = this._ownerDocument.createElement("tbody");
+      tBody.appendChild(tr);
+      this.appendChild(tBody);
+    } else if (this.rows.length === 0) {
+      const tBody = this.tBodies.item(this.tBodies.length - 1);
+      tBody.appendChild(tr);
+    } else if (index === -1 || index === this.rows.length) {
+      const tSection = this.rows.item(this.rows.length - 1).parentNode;
+      tSection.appendChild(tr);
+    } else {
+      const beforeTR = this.rows.item(index);
+      const tSection = beforeTR.parentNode;
+      tSection.insertBefore(tr, beforeTR);
+    }
+
+    return tr;
+  }
+
+  deleteRow(index) {
+    const rowLength = this.rows.length;
+    if (index < -1 || index >= rowLength) {
+      throw DOMException.create(this._globalObject, [
+        `Cannot delete a row at index ${index}, where no row exists`,
+        "IndexSizeError"
+      ]);
+    }
+
+    if (index === -1) {
+      if (rowLength === 0) {
+        return;
+      }
+
+      index = rowLength - 1;
+    }
+
+    const tr = this.rows.item(index);
+    tr.parentNode.removeChild(tr);
+  }
+}
+
+module.exports = {
+  implementation: HTMLTableElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableRowElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,88 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const HTMLCollection = require("../generated/HTMLCollection");
+const { HTML_NS } = require("../helpers/namespaces");
+const { childrenByLocalNames } = require("../helpers/traversal");
+const { domSymbolTree } = require("../helpers/internal-constants");
+
+const cellLocalNames = new Set(["td", "th"]);
+
+class HTMLTableRowElementImpl extends HTMLElementImpl {
+  get cells() {
+    if (!this._cells) {
+      this._cells = HTMLCollection.createImpl(this._globalObject, [], {
+        element: this,
+        query: () => childrenByLocalNames(this, cellLocalNames)
+      });
+    }
+    return this._cells;
+  }
+
+  get rowIndex() {
+    const parent = this.parentElement;
+    if (parent === null || parent.namespaceURI !== HTML_NS) {
+      return -1;
+    }
+
+    let tableElement = parent;
+    if (parent.localName === "thead" || parent.localName === "tbody" || parent.localName === "tfoot") {
+      tableElement = parent.parentElement;
+    }
+    if (tableElement === null || tableElement.namespaceURI !== HTML_NS || tableElement.localName !== "table") {
+      return -1;
+    }
+
+    return tableElement.rows.indexOf(this);
+  }
+
+  get sectionRowIndex() {
+    const parent = domSymbolTree.parent(this);
+    if (parent === null) {
+      return -1;
+    }
+
+    const { rows } = parent;
+    if (!rows) {
+      return -1;
+    }
+
+    return rows.indexOf(this);
+  }
+
+  insertCell(index) {
+    const td = this._ownerDocument.createElement("TD");
+    const { cells } = this;
+    if (index < -1 || index > cells.length) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    if (index === -1 || index === cells.length) {
+      this._append(td);
+    } else {
+      const ref = cells.item(index);
+      this._insert(td, ref);
+    }
+    return td;
+  }
+
+  deleteCell(index) {
+    const { cells } = this;
+    if (index < -1 || index >= cells.length) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    if (index === -1) {
+      if (cells.length === 0) {
+        return;
+      }
+
+      index = cells.length - 1;
+    }
+    const td = cells.item(index);
+    this._remove(td);
+  }
+}
+
+module.exports = {
+  implementation: HTMLTableRowElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTableSectionElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,61 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { childrenByLocalName } = require("../helpers/traversal");
+const HTMLCollection = require("../generated/HTMLCollection");
+const DOMException = require("domexception/webidl2js-wrapper");
+
+class HTMLTableSectionElementImpl extends HTMLElementImpl {
+  get rows() {
+    if (!this._rows) {
+      this._rows = HTMLCollection.createImpl(this._globalObject, [], {
+        element: this,
+        query: () => childrenByLocalName(this, "tr")
+      });
+    }
+    return this._rows;
+  }
+
+  insertRow(index) {
+    if (index < -1 || index > this.rows.length) {
+      throw DOMException.create(this._globalObject, [
+        "Cannot insert a row at an index that is less than -1 or greater than the number of existing rows",
+        "IndexSizeError"
+      ]);
+    }
+
+    const tr = this._ownerDocument.createElement("tr");
+
+    if (index === -1 || index === this.rows.length) {
+      this._append(tr);
+    } else {
+      const beforeTR = this.rows.item(index);
+      this._insert(tr, beforeTR);
+    }
+
+    return tr;
+  }
+
+  deleteRow(index) {
+    if (index < -1 || index >= this.rows.length) {
+      throw DOMException.create(this._globalObject, [
+        `Cannot delete a row at index ${index}, where no row exists`,
+        "IndexSizeError"
+      ]);
+    }
+
+    if (index === -1) {
+      if (this.rows.length > 0) {
+        const tr = this.rows.item(this.rows.length - 1);
+        this._remove(tr);
+      }
+    } else {
+      const tr = this.rows.item(index);
+      this._remove(tr);
+    }
+  }
+}
+
+module.exports = {
+  implementation: HTMLTableSectionElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTemplateElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,67 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const Document = require("../generated/Document");
+const DocumentFragment = require("../generated/DocumentFragment");
+
+const { cloningSteps, domSymbolTree } = require("../helpers/internal-constants");
+const { clone } = require("../node");
+
+class HTMLTemplateElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    const doc = this._appropriateTemplateContentsOwnerDocument(this._ownerDocument);
+    this._templateContents = DocumentFragment.createImpl(this._globalObject, [], {
+      ownerDocument: doc,
+      host: this
+    });
+  }
+
+  // https://html.spec.whatwg.org/multipage/scripting.html#appropriate-template-contents-owner-document
+  _appropriateTemplateContentsOwnerDocument(doc) {
+    if (!doc._isInertTemplateDocument) {
+      if (doc._associatedInertTemplateDocument === undefined) {
+        const newDoc = Document.createImpl(this._globalObject, [], {
+          options: {
+            parsingMode: doc._parsingMode,
+            encoding: doc._encoding
+          }
+        });
+        newDoc._isInertTemplateDocument = true;
+
+        doc._associatedInertTemplateDocument = newDoc;
+      }
+
+      doc = doc._associatedInertTemplateDocument;
+    }
+
+    return doc;
+  }
+
+  // https://html.spec.whatwg.org/multipage/scripting.html#template-adopting-steps
+  _adoptingSteps() {
+    const doc = this._appropriateTemplateContentsOwnerDocument(this._ownerDocument);
+    doc._adoptNode(this._templateContents);
+  }
+
+  get content() {
+    return this._templateContents;
+  }
+
+  [cloningSteps](copy, node, document, cloneChildren) {
+    if (!cloneChildren) {
+      return;
+    }
+
+    for (const child of domSymbolTree.childrenIterator(node._templateContents)) {
+      const childCopy = clone(child, copy._templateContents._ownerDocument, true);
+      copy._templateContents.appendChild(childCopy);
+    }
+  }
+}
+
+module.exports = {
+  implementation: HTMLTemplateElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTextAreaElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,272 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+const DefaultConstraintValidationImpl =
+  require("../constraint-validation/DefaultConstraintValidation-impl").implementation;
+const ValidityState = require("../generated/ValidityState");
+const { mixin } = require("../../utils");
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { cloningSteps } = require("../helpers/internal-constants");
+const { isDisabled, getLabelsForLabelable, formOwner } = require("../helpers/form-controls");
+const { childTextContent } = require("../helpers/text");
+const { fireAnEvent } = require("../helpers/events");
+
+class HTMLTextAreaElementImpl extends HTMLElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._selectionStart = this._selectionEnd = 0;
+    this._selectionDirection = "none";
+    this._rawValue = "";
+    this._dirtyValue = false;
+
+    this._customValidityErrorMessage = "";
+
+    this._labels = null;
+  }
+
+  _formReset() {
+    this._rawValue = childTextContent(this);
+    this._dirtyValue = false;
+  }
+
+  _getAPIValue() {
+    return this._rawValue.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#textarea-wrapping-transformation
+  _getValue() {
+    const apiValue = this._getAPIValue();
+    const wrap = this.getAttributeNS(null, "wrap");
+    return wrap === "hard" ?
+      textareaWrappingTransformation(apiValue, this.cols) :
+      apiValue;
+  }
+
+  _childTextContentChangeSteps() {
+    super._childTextContentChangeSteps();
+
+    if (this._dirtyValue === false) {
+      this._rawValue = childTextContent(this);
+    }
+  }
+
+  get labels() {
+    return getLabelsForLabelable(this);
+  }
+
+  get form() {
+    return formOwner(this);
+  }
+
+  get defaultValue() {
+    return childTextContent(this);
+  }
+
+  set defaultValue(val) {
+    this.textContent = val;
+  }
+
+  get value() {
+    return this._getAPIValue();
+  }
+
+  set value(val) {
+    // https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-value
+    const oldAPIValue = this._getAPIValue();
+    this._rawValue = val;
+    this._dirtyValue = true;
+
+    if (oldAPIValue !== this._getAPIValue()) {
+      this._selectionStart = this._selectionEnd = this._getValueLength();
+      this._selectionDirection = "none";
+    }
+  }
+
+  get textLength() {
+    return this.value.length; // code unit length (16 bit)
+  }
+
+  get type() {
+    return "textarea";
+  }
+
+  _dispatchSelectEvent() {
+    fireAnEvent("select", this, undefined, { bubbles: true, cancelable: true });
+  }
+
+  _getValueLength() {
+    return typeof this.value === "string" ? this.value.length : 0;
+  }
+
+  select() {
+    this._selectionStart = 0;
+    this._selectionEnd = this._getValueLength();
+    this._selectionDirection = "none";
+    this._dispatchSelectEvent();
+  }
+
+  get selectionStart() {
+    return this._selectionStart;
+  }
+
+  set selectionStart(start) {
+    this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
+  }
+
+  get selectionEnd() {
+    return this._selectionEnd;
+  }
+
+  set selectionEnd(end) {
+    this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
+  }
+
+  get selectionDirection() {
+    return this._selectionDirection;
+  }
+
+  set selectionDirection(dir) {
+    this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
+  }
+
+  setSelectionRange(start, end, dir) {
+    this._selectionEnd = Math.min(end, this._getValueLength());
+    this._selectionStart = Math.min(start, this._selectionEnd);
+    this._selectionDirection = dir === "forward" || dir === "backward" ? dir : "none";
+    this._dispatchSelectEvent();
+  }
+
+  setRangeText(repl, start, end, selectionMode = "preserve") {
+    if (arguments.length < 2) {
+      start = this._selectionStart;
+      end = this._selectionEnd;
+    } else if (start > end) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+
+    start = Math.min(start, this._getValueLength());
+    end = Math.min(end, this._getValueLength());
+
+    const val = this.value;
+    let selStart = this._selectionStart;
+    let selEnd = this._selectionEnd;
+
+    this.value = val.slice(0, start) + repl + val.slice(end);
+
+    const newEnd = start + this.value.length;
+
+    if (selectionMode === "select") {
+      this.setSelectionRange(start, newEnd);
+    } else if (selectionMode === "start") {
+      this.setSelectionRange(start, start);
+    } else if (selectionMode === "end") {
+      this.setSelectionRange(newEnd, newEnd);
+    } else { // preserve
+      const delta = repl.length - (end - start);
+
+      if (selStart > end) {
+        selStart += delta;
+      } else if (selStart > start) {
+        selStart = start;
+      }
+
+      if (selEnd > end) {
+        selEnd += delta;
+      } else if (selEnd > start) {
+        selEnd = newEnd;
+      }
+
+      this.setSelectionRange(selStart, selEnd);
+    }
+  }
+
+  get cols() {
+    if (!this.hasAttributeNS(null, "cols")) {
+      return 20;
+    }
+    return parseInt(this.getAttributeNS(null, "cols"));
+  }
+
+  set cols(value) {
+    if (value <= 0) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    this.setAttributeNS(null, "cols", String(value));
+  }
+
+  get rows() {
+    if (!this.hasAttributeNS(null, "rows")) {
+      return 2;
+    }
+    return parseInt(this.getAttributeNS(null, "rows"));
+  }
+
+  set rows(value) {
+    if (value <= 0) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+    this.setAttributeNS(null, "rows", String(value));
+  }
+
+  _barredFromConstraintValidationSpecialization() {
+    return this.hasAttributeNS(null, "readonly");
+  }
+
+  get _mutable() {
+    return !isDisabled(this) && !this.hasAttributeNS(null, "readonly");
+  }
+
+  // https://html.spec.whatwg.org/multipage/form-elements.html#attr-textarea-required
+  get validity() {
+    if (!this._validity) {
+      const state = {
+        valueMissing: () => this.hasAttributeNS(null, "required") && this._mutable && this.value === ""
+      };
+
+      this._validity = ValidityState.createImpl(this._globalObject, [], {
+        element: this,
+        state
+      });
+    }
+    return this._validity;
+  }
+
+  [cloningSteps](copy, node) {
+    copy._dirtyValue = node._dirtyValue;
+    copy._rawValue = node._rawValue;
+  }
+}
+
+mixin(HTMLTextAreaElementImpl.prototype, DefaultConstraintValidationImpl.prototype);
+
+module.exports = {
+  implementation: HTMLTextAreaElementImpl
+};
+
+function textareaWrappingTransformation(text, cols) {
+  let lineStart = 0;
+  let lineEnd = text.indexOf("\n");
+  if (lineEnd === -1) {
+    lineEnd = text.length;
+  }
+
+  while (lineStart < text.length) {
+    const lineLength = lineEnd - lineStart;
+    if (lineLength > cols) {
+      // split the line
+      lineEnd = lineStart + cols;
+      text = text.slice(0, lineEnd) + "\n" + text.slice(lineEnd);
+    }
+    // move to next line
+    lineStart = lineEnd + 1; // step over the newline
+    lineEnd = text.indexOf("\n", lineStart);
+    if (lineEnd === -1) {
+      lineEnd = text.length;
+    }
+  }
+
+  return text;
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTimeElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTimeElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLTimeElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTitleElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,18 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+const { childTextContent } = require("../helpers/text");
+
+class HTMLTitleElementImpl extends HTMLElementImpl {
+  get text() {
+    return childTextContent(this);
+  }
+
+  set text(value) {
+    this.textContent = value;
+  }
+}
+
+module.exports = {
+  implementation: HTMLTitleElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLTrackElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLTrackElementImpl extends HTMLElementImpl {
+  get readyState() {
+    return 0;
+  }
+}
+
+module.exports = {
+  implementation: HTMLTrackElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUListElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLUListElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLUListElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLUnknownElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const HTMLElementImpl = require("./HTMLElement-impl").implementation;
+
+class HTMLUnknownElementImpl extends HTMLElementImpl { }
+
+module.exports = {
+  implementation: HTMLUnknownElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/HTMLVideoElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+
+const HTMLMediaElementImpl = require("./HTMLMediaElement-impl").implementation;
+
+class HTMLVideoElementImpl extends HTMLMediaElementImpl {
+  get videoWidth() {
+    return 0;
+  }
+
+  get videoHeight() {
+    return 0;
+  }
+}
+
+module.exports = {
+  implementation: HTMLVideoElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/LinkStyle-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,2 @@
+"use strict";
+module.exports = class LinkStyleImpl {};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/Node-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1165 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+const { simultaneousIterators } = require("../../utils");
+const NODE_TYPE = require("../node-type");
+const NODE_DOCUMENT_POSITION = require("../node-document-position");
+const { clone, locateNamespacePrefix, locateNamespace } = require("../node");
+const { setAnExistingAttributeValue } = require("../attributes");
+
+const NodeList = require("../generated/NodeList");
+
+const { nodeRoot, nodeLength } = require("../helpers/node");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { documentBaseURLSerialized } = require("../helpers/document-base-url");
+const { queueTreeMutationRecord } = require("../helpers/mutation-observers");
+const { enqueueCECallbackReaction, tryUpgradeElement } = require("../helpers/custom-elements");
+const {
+  isShadowRoot, shadowIncludingRoot, assignSlot, assignSlotableForTree, assignSlotable, signalSlotChange, isSlot,
+  shadowIncludingInclusiveDescendantsIterator, shadowIncludingDescendantsIterator
+} = require("../helpers/shadow-dom");
+
+function isObsoleteNodeType(node) {
+  return node.nodeType === NODE_TYPE.ENTITY_NODE ||
+    node.nodeType === NODE_TYPE.ENTITY_REFERENCE_NODE ||
+    node.nodeType === NODE_TYPE.NOTATION_NODE ||
+    node.nodeType === NODE_TYPE.CDATA_SECTION_NODE;
+}
+
+function nodeEquals(a, b) {
+  if (a.nodeType !== b.nodeType) {
+    return false;
+  }
+
+  switch (a.nodeType) {
+    case NODE_TYPE.DOCUMENT_TYPE_NODE:
+      if (a.name !== b.name || a.publicId !== b.publicId ||
+          a.systemId !== b.systemId) {
+        return false;
+      }
+      break;
+    case NODE_TYPE.ELEMENT_NODE:
+      if (a._namespaceURI !== b._namespaceURI || a._prefix !== b._prefix || a._localName !== b._localName ||
+          a._attributes.length !== b._attributes.length) {
+        return false;
+      }
+      break;
+    case NODE_TYPE.ATTRIBUTE_NODE:
+      if (a._namespace !== b._namespace || a._localName !== b._localName || a._value !== b._value) {
+        return false;
+      }
+      break;
+    case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+      if (a._target !== b._target || a._data !== b._data) {
+        return false;
+      }
+      break;
+    case NODE_TYPE.TEXT_NODE:
+    case NODE_TYPE.COMMENT_NODE:
+      if (a._data !== b._data) {
+        return false;
+      }
+      break;
+  }
+
+  if (a.nodeType === NODE_TYPE.ELEMENT_NODE && !attributeListsEqual(a, b)) {
+    return false;
+  }
+
+  for (const nodes of simultaneousIterators(domSymbolTree.childrenIterator(a), domSymbolTree.childrenIterator(b))) {
+    if (!nodes[0] || !nodes[1]) {
+      // mismatch in the amount of childNodes
+      return false;
+    }
+
+    if (!nodeEquals(nodes[0], nodes[1])) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// Needed by https://dom.spec.whatwg.org/#concept-node-equals
+function attributeListsEqual(elementA, elementB) {
+  const listA = elementA._attributeList;
+  const listB = elementB._attributeList;
+
+  const lengthA = listA.length;
+  const lengthB = listB.length;
+
+  if (lengthA !== lengthB) {
+    return false;
+  }
+
+  for (let i = 0; i < lengthA; ++i) {
+    const attrA = listA[i];
+
+    if (!listB.some(attrB => nodeEquals(attrA, attrB))) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// https://dom.spec.whatwg.org/#concept-tree-host-including-inclusive-ancestor
+function isHostInclusiveAncestor(nodeImplA, nodeImplB) {
+  for (const ancestor of domSymbolTree.ancestorsIterator(nodeImplB)) {
+    if (ancestor === nodeImplA) {
+      return true;
+    }
+  }
+
+  const rootImplB = nodeRoot(nodeImplB);
+  if (rootImplB._host) {
+    return isHostInclusiveAncestor(nodeImplA, rootImplB._host);
+  }
+
+  return false;
+}
+
+class NodeImpl extends EventTargetImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    domSymbolTree.initialize(this);
+
+    this._ownerDocument = privateData.ownerDocument;
+
+    this._childNodesList = null;
+    this._childrenList = null;
+    this._version = 0;
+    this._memoizedQueries = {};
+    this._registeredObserverList = [];
+    this._referencedRanges = new Set();
+  }
+
+  _getTheParent() {
+    if (this._assignedSlot) {
+      return this._assignedSlot;
+    }
+
+    return domSymbolTree.parent(this);
+  }
+
+  get parentNode() {
+    return domSymbolTree.parent(this);
+  }
+
+  getRootNode(options) {
+    return options.composed ? shadowIncludingRoot(this) : nodeRoot(this);
+  }
+
+  get nodeName() {
+    switch (this.nodeType) {
+      case NODE_TYPE.ELEMENT_NODE:
+        return this.tagName;
+      case NODE_TYPE.ATTRIBUTE_NODE:
+        return this._qualifiedName;
+      case NODE_TYPE.TEXT_NODE:
+        return "#text";
+      case NODE_TYPE.CDATA_SECTION_NODE:
+        return "#cdata-section";
+      case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+        return this.target;
+      case NODE_TYPE.COMMENT_NODE:
+        return "#comment";
+      case NODE_TYPE.DOCUMENT_NODE:
+        return "#document";
+      case NODE_TYPE.DOCUMENT_TYPE_NODE:
+        return this.name;
+      case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+        return "#document-fragment";
+    }
+
+    // should never happen
+    return null;
+  }
+
+  get firstChild() {
+    return domSymbolTree.firstChild(this);
+  }
+
+  // https://dom.spec.whatwg.org/#connected
+  // https://dom.spec.whatwg.org/#dom-node-isconnected
+  get isConnected() {
+    const root = shadowIncludingRoot(this);
+    return root && root.nodeType === NODE_TYPE.DOCUMENT_NODE;
+  }
+
+  get ownerDocument() {
+    return this.nodeType === NODE_TYPE.DOCUMENT_NODE ? null : this._ownerDocument;
+  }
+
+  get lastChild() {
+    return domSymbolTree.lastChild(this);
+  }
+
+  get childNodes() {
+    if (!this._childNodesList) {
+      this._childNodesList = NodeList.createImpl(this._globalObject, [], {
+        element: this,
+        query: () => domSymbolTree.childrenToArray(this)
+      });
+    } else {
+      this._childNodesList._update();
+    }
+
+    return this._childNodesList;
+  }
+
+  get nextSibling() {
+    return domSymbolTree.nextSibling(this);
+  }
+
+  get previousSibling() {
+    return domSymbolTree.previousSibling(this);
+  }
+
+  _modified() {
+    this._version++;
+    for (const ancestor of domSymbolTree.ancestorsIterator(this)) {
+      ancestor._version++;
+    }
+
+    if (this._childrenList) {
+      this._childrenList._update();
+    }
+    if (this._childNodesList) {
+      this._childNodesList._update();
+    }
+    this._clearMemoizedQueries();
+  }
+
+  _childTextContentChangeSteps() {
+    // Default: do nothing
+  }
+
+  _clearMemoizedQueries() {
+    this._memoizedQueries = {};
+    const myParent = domSymbolTree.parent(this);
+    if (myParent) {
+      myParent._clearMemoizedQueries();
+    }
+  }
+
+  _descendantRemoved(parent, child) {
+    const myParent = domSymbolTree.parent(this);
+    if (myParent) {
+      myParent._descendantRemoved(parent, child);
+    }
+  }
+
+  _descendantAdded(parent, child) {
+    const myParent = domSymbolTree.parent(this);
+    if (myParent) {
+      myParent._descendantAdded(parent, child);
+    }
+  }
+
+  _attach() {
+    this._attached = true;
+
+    for (const child of domSymbolTree.childrenIterator(this)) {
+      if (child._attach) {
+        child._attach();
+      }
+    }
+  }
+
+  _detach() {
+    this._attached = false;
+
+    if (this._ownerDocument && this._ownerDocument._lastFocusedElement === this) {
+      this._ownerDocument._lastFocusedElement = null;
+    }
+
+    for (const child of domSymbolTree.childrenIterator(this)) {
+      if (child._detach) {
+        child._detach();
+      }
+    }
+  }
+
+  hasChildNodes() {
+    return domSymbolTree.hasChildren(this);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-node-normalize
+  normalize() {
+    // It is important to use a treeToArray instead of a treeToIterator here, because the
+    // treeToIterator doesn't support tree mutation in the middle of the traversal.
+    for (const node of domSymbolTree.treeToArray(this)) {
+      const parentNode = domSymbolTree.parent(node);
+      if (parentNode === null || node.nodeType !== NODE_TYPE.TEXT_NODE) {
+        continue;
+      }
+
+      let length = nodeLength(node);
+
+      if (length === 0) {
+        parentNode._remove(node);
+        continue;
+      }
+
+      const continuousExclusiveTextNodes = [];
+
+      for (const currentNode of domSymbolTree.previousSiblingsIterator(node)) {
+        if (currentNode.nodeType !== NODE_TYPE.TEXT_NODE) {
+          break;
+        }
+
+        continuousExclusiveTextNodes.unshift(currentNode);
+      }
+      for (const currentNode of domSymbolTree.nextSiblingsIterator(node)) {
+        if (currentNode.nodeType !== NODE_TYPE.TEXT_NODE) {
+          break;
+        }
+
+        continuousExclusiveTextNodes.push(currentNode);
+      }
+
+      const data = continuousExclusiveTextNodes.reduce((d, n) => d + n._data, "");
+      node.replaceData(length, 0, data);
+
+      let currentNode = domSymbolTree.nextSibling(node);
+      while (currentNode && currentNode.nodeType !== NODE_TYPE.TEXT_NODE) {
+        const currentNodeParent = domSymbolTree.parent(currentNode);
+        const currentNodeIndex = domSymbolTree.index(currentNode);
+
+        for (const range of node._referencedRanges) {
+          const { _start, _end } = range;
+
+          if (_start.node === currentNode) {
+            range._setLiveRangeStart(node, _start.offset + length);
+          }
+          if (_end.node === currentNode) {
+            range._setLiveRangeEnd(node, _end.offset + length);
+          }
+          if (_start.node === currentNodeParent && _start.offset === currentNodeIndex) {
+            range._setLiveRangeStart(node, length);
+          }
+          if (_end.node === currentNodeParent && _end.offset === currentNodeIndex) {
+            range._setLiveRangeStart(node, length);
+          }
+        }
+
+        length += nodeLength(currentNode);
+        currentNode = domSymbolTree.nextSibling(currentNode);
+      }
+
+      for (const continuousExclusiveTextNode of continuousExclusiveTextNodes) {
+        parentNode._remove(continuousExclusiveTextNode);
+      }
+    }
+  }
+
+  get parentElement() {
+    const parentNode = domSymbolTree.parent(this);
+    return parentNode !== null && parentNode.nodeType === NODE_TYPE.ELEMENT_NODE ? parentNode : null;
+  }
+
+  get baseURI() {
+    return documentBaseURLSerialized(this._ownerDocument);
+  }
+
+  compareDocumentPosition(other) {
+    // Let node1 be other and node2 be the context object.
+    let node1 = other;
+    let node2 = this;
+
+    if (isObsoleteNodeType(node2) || isObsoleteNodeType(node1)) {
+      throw new Error("Obsolete node type");
+    }
+
+    let attr1 = null;
+    let attr2 = null;
+
+    if (node1.nodeType === NODE_TYPE.ATTRIBUTE_NODE) {
+      attr1 = node1;
+      node1 = attr1._element;
+    }
+
+    if (node2.nodeType === NODE_TYPE.ATTRIBUTE_NODE) {
+      attr2 = node2;
+      node2 = attr2._element;
+
+      if (attr1 !== null && node1 !== null && node2 === node1) {
+        for (const attr of node2._attributeList) {
+          if (nodeEquals(attr, attr1)) {
+            return NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
+              NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_PRECEDING;
+          }
+
+          if (nodeEquals(attr, attr2)) {
+            return NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
+              NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_FOLLOWING;
+          }
+        }
+      }
+    }
+
+    const result = domSymbolTree.compareTreePosition(node2, node1);
+
+    // “If other and reference are not in the same tree, return the result of adding DOCUMENT_POSITION_DISCONNECTED,
+    //  DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, and either DOCUMENT_POSITION_PRECEDING or
+    // DOCUMENT_POSITION_FOLLOWING, with the constraint that this is to be consistent, together.”
+    if (result === NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_DISCONNECTED) {
+      // symbol-tree does not add these bits required by the spec:
+      return NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_DISCONNECTED |
+        NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
+        NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_FOLLOWING;
+    }
+
+    return result;
+  }
+
+  lookupPrefix(namespace) {
+    if (namespace === null || namespace === "") {
+      return null;
+    }
+
+    switch (this.nodeType) {
+      case NODE_TYPE.ELEMENT_NODE: {
+        return locateNamespacePrefix(this, namespace);
+      }
+      case NODE_TYPE.DOCUMENT_NODE: {
+        return this.documentElement !== null ? locateNamespacePrefix(this.documentElement, namespace) : null;
+      }
+      case NODE_TYPE.DOCUMENT_TYPE_NODE:
+      case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+        return null;
+      }
+      case NODE_TYPE.ATTRIBUTE_NODE: {
+        return this._element !== null ? locateNamespacePrefix(this._element, namespace) : null;
+      }
+      default: {
+        return this.parentElement !== null ? locateNamespacePrefix(this.parentElement, namespace) : null;
+      }
+    }
+  }
+
+  lookupNamespaceURI(prefix) {
+    if (prefix === "") {
+      prefix = null;
+    }
+
+    return locateNamespace(this, prefix);
+  }
+
+  isDefaultNamespace(namespace) {
+    if (namespace === "") {
+      namespace = null;
+    }
+
+    const defaultNamespace = locateNamespace(this, null);
+    return defaultNamespace === namespace;
+  }
+
+  contains(other) {
+    if (other === null) {
+      return false;
+    } else if (this === other) {
+      return true;
+    }
+    return Boolean(this.compareDocumentPosition(other) & NODE_DOCUMENT_POSITION.DOCUMENT_POSITION_CONTAINED_BY);
+  }
+
+  isEqualNode(node) {
+    if (node === null) {
+      return false;
+    }
+
+    // Fast-path, not in the spec
+    if (this === node) {
+      return true;
+    }
+
+    return nodeEquals(this, node);
+  }
+
+  isSameNode(node) {
+    if (this === node) {
+      return true;
+    }
+
+    return false;
+  }
+
+  cloneNode(deep) {
+    if (isShadowRoot(this)) {
+      throw DOMException.create(this._globalObject, ["ShadowRoot nodes are not clonable.", "NotSupportedError"]);
+    }
+
+    deep = Boolean(deep);
+
+    return clone(this, undefined, deep);
+  }
+
+  get nodeValue() {
+    switch (this.nodeType) {
+      case NODE_TYPE.ATTRIBUTE_NODE: {
+        return this._value;
+      }
+      case NODE_TYPE.TEXT_NODE:
+      case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+      case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+      case NODE_TYPE.COMMENT_NODE: {
+        return this._data;
+      }
+      default: {
+        return null;
+      }
+    }
+  }
+
+  set nodeValue(value) {
+    if (value === null) {
+      value = "";
+    }
+
+    switch (this.nodeType) {
+      case NODE_TYPE.ATTRIBUTE_NODE: {
+        setAnExistingAttributeValue(this, value);
+        break;
+      }
+      case NODE_TYPE.TEXT_NODE:
+      case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+      case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+      case NODE_TYPE.COMMENT_NODE: {
+        this.replaceData(0, this.length, value);
+        break;
+      }
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#dom-node-textcontent
+  get textContent() {
+    switch (this.nodeType) {
+      case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+      case NODE_TYPE.ELEMENT_NODE: {
+        let text = "";
+        for (const child of domSymbolTree.treeIterator(this)) {
+          if (child.nodeType === NODE_TYPE.TEXT_NODE || child.nodeType === NODE_TYPE.CDATA_SECTION_NODE) {
+            text += child.nodeValue;
+          }
+        }
+        return text;
+      }
+
+      case NODE_TYPE.ATTRIBUTE_NODE: {
+        return this._value;
+      }
+
+      case NODE_TYPE.TEXT_NODE:
+      case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+      case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+      case NODE_TYPE.COMMENT_NODE: {
+        return this._data;
+      }
+
+      default: {
+        return null;
+      }
+    }
+  }
+  set textContent(value) {
+    if (value === null) {
+      value = "";
+    }
+
+    switch (this.nodeType) {
+      case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+      case NODE_TYPE.ELEMENT_NODE: {
+        // https://dom.spec.whatwg.org/#string-replace-all
+        let nodeImpl = null;
+
+        if (value !== "") {
+          nodeImpl = this._ownerDocument.createTextNode(value);
+        }
+
+        this._replaceAll(nodeImpl);
+        break;
+      }
+
+      case NODE_TYPE.ATTRIBUTE_NODE: {
+        setAnExistingAttributeValue(this, value);
+        break;
+      }
+
+      case NODE_TYPE.TEXT_NODE:
+      case NODE_TYPE.CDATA_SECTION_NODE: // CDATASection is a subclass of Text
+      case NODE_TYPE.PROCESSING_INSTRUCTION_NODE:
+      case NODE_TYPE.COMMENT_NODE: {
+        this.replaceData(0, this.length, value);
+        break;
+      }
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#dom-node-insertbefore
+  insertBefore(nodeImpl, childImpl) {
+    return this._preInsert(nodeImpl, childImpl);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-node-appendchild
+  appendChild(nodeImpl) {
+    return this._append(nodeImpl);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-node-replacechild
+  replaceChild(nodeImpl, childImpl) {
+    return this._replace(nodeImpl, childImpl);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-node-removechild
+  removeChild(oldChildImpl) {
+    return this._preRemove(oldChildImpl);
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
+  _preInsertValidity(nodeImpl, childImpl) {
+    const { nodeType, nodeName } = nodeImpl;
+    const { nodeType: parentType, nodeName: parentName } = this;
+
+    if (
+      parentType !== NODE_TYPE.DOCUMENT_NODE &&
+      parentType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+      parentType !== NODE_TYPE.ELEMENT_NODE
+    ) {
+      throw DOMException.create(this._globalObject, [
+        `Node can't be inserted in a ${parentName} parent.`,
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (isHostInclusiveAncestor(nodeImpl, this)) {
+      throw DOMException.create(this._globalObject, [
+        "The operation would yield an incorrect node tree.",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (childImpl && domSymbolTree.parent(childImpl) !== this) {
+      throw DOMException.create(this._globalObject, [
+        "The child can not be found in the parent.",
+        "NotFoundError"
+      ]);
+    }
+
+    if (
+      nodeType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+      nodeType !== NODE_TYPE.DOCUMENT_TYPE_NODE &&
+      nodeType !== NODE_TYPE.ELEMENT_NODE &&
+      nodeType !== NODE_TYPE.TEXT_NODE &&
+      nodeType !== NODE_TYPE.CDATA_SECTION_NODE && // CData section extends from Text
+      nodeType !== NODE_TYPE.PROCESSING_INSTRUCTION_NODE &&
+      nodeType !== NODE_TYPE.COMMENT_NODE
+    ) {
+      throw DOMException.create(this._globalObject, [
+        `${nodeName} node can't be inserted in parent node.`,
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (
+      (nodeType === NODE_TYPE.TEXT_NODE && parentType === NODE_TYPE.DOCUMENT_NODE) ||
+      (nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE && parentType !== NODE_TYPE.DOCUMENT_NODE)
+    ) {
+      throw DOMException.create(this._globalObject, [
+        `${nodeName} node can't be inserted in ${parentName} parent.`,
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (parentType === NODE_TYPE.DOCUMENT_NODE) {
+      const nodeChildren = domSymbolTree.childrenToArray(nodeImpl);
+      const parentChildren = domSymbolTree.childrenToArray(this);
+
+      switch (nodeType) {
+        case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+          const nodeChildrenElements = nodeChildren.filter(child => child.nodeType === NODE_TYPE.ELEMENT_NODE);
+          if (nodeChildrenElements.length > 1) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+
+          const hasNodeTextChildren = nodeChildren.some(child => child.nodeType === NODE_TYPE.TEXT_NODE);
+          if (hasNodeTextChildren) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+
+          if (
+            nodeChildrenElements.length === 1 &&
+            (
+              parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE) ||
+              (childImpl && childImpl.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) ||
+              (
+                childImpl &&
+                domSymbolTree.nextSibling(childImpl) &&
+                domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+              )
+            )
+          ) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+          break;
+        }
+
+        case NODE_TYPE.ELEMENT_NODE:
+          if (
+            parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE) ||
+            (childImpl && childImpl.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) ||
+            (
+              childImpl &&
+              domSymbolTree.nextSibling(childImpl) &&
+              domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+            )
+          ) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+          break;
+
+        case NODE_TYPE.DOCUMENT_TYPE_NODE:
+          if (
+            parentChildren.some(child => child.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) ||
+            (
+              childImpl &&
+              domSymbolTree.previousSibling(childImpl) &&
+              domSymbolTree.previousSibling(childImpl).nodeType === NODE_TYPE.ELEMENT_NODE
+            ) ||
+            (!childImpl && parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE))
+          ) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+          break;
+      }
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-pre-insert
+  _preInsert(nodeImpl, childImpl) {
+    this._preInsertValidity(nodeImpl, childImpl);
+
+    let referenceChildImpl = childImpl;
+    if (referenceChildImpl === nodeImpl) {
+      referenceChildImpl = domSymbolTree.nextSibling(nodeImpl);
+    }
+
+    this._ownerDocument._adoptNode(nodeImpl);
+
+    this._insert(nodeImpl, referenceChildImpl);
+
+    return nodeImpl;
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-insert
+  _insert(nodeImpl, childImpl, suppressObservers) {
+    const count = nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ?
+        domSymbolTree.childrenCount(nodeImpl) :
+        1;
+
+    if (childImpl) {
+      const childIndex = domSymbolTree.index(childImpl);
+
+      for (const range of this._referencedRanges) {
+        const { _start, _end } = range;
+
+        if (_start.offset > childIndex) {
+          range._setLiveRangeStart(this, _start.offset + count);
+        }
+
+        if (_end.offset > childIndex) {
+          range._setLiveRangeEnd(this, _end.offset + count);
+        }
+      }
+    }
+
+    const nodesImpl = nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ?
+      domSymbolTree.childrenToArray(nodeImpl) :
+      [nodeImpl];
+
+    if (nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+      let grandChildImpl;
+      while ((grandChildImpl = domSymbolTree.firstChild(nodeImpl))) {
+        nodeImpl._remove(grandChildImpl, true);
+      }
+    }
+
+    if (nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+      queueTreeMutationRecord(nodeImpl, [], nodesImpl, null, null);
+    }
+
+    const previousChildImpl = childImpl ?
+      domSymbolTree.previousSibling(childImpl) :
+      domSymbolTree.lastChild(this);
+
+    for (const node of nodesImpl) {
+      if (!childImpl) {
+        domSymbolTree.appendChild(this, node);
+      } else {
+        domSymbolTree.insertBefore(childImpl, node);
+      }
+
+      if (
+        (this.nodeType === NODE_TYPE.ELEMENT_NODE && this._shadowRoot !== null) &&
+        (node.nodeType === NODE_TYPE.ELEMENT_NODE || node.nodeType === NODE_TYPE.TEXT_NODE)
+      ) {
+        assignSlot(node);
+      }
+
+      this._modified();
+
+      if (node.nodeType === NODE_TYPE.TEXT_NODE ||
+          node.nodeType === NODE_TYPE.CDATA_SECTION_NODE) {
+        this._childTextContentChangeSteps();
+      }
+
+      if (isSlot(this) && this._assignedNodes.length === 0 && isShadowRoot(nodeRoot(this))) {
+        signalSlotChange(this);
+      }
+
+      const root = nodeRoot(node);
+      if (isShadowRoot(root)) {
+        assignSlotableForTree(root);
+      }
+
+      if (this._attached && nodeImpl._attach) {
+        node._attach();
+      }
+
+      this._descendantAdded(this, node);
+
+      for (const inclusiveDescendant of shadowIncludingInclusiveDescendantsIterator(node)) {
+        if (inclusiveDescendant.isConnected) {
+          if (inclusiveDescendant._ceState === "custom") {
+            enqueueCECallbackReaction(inclusiveDescendant, "connectedCallback", []);
+          } else {
+            tryUpgradeElement(inclusiveDescendant);
+          }
+        }
+      }
+    }
+
+    if (!suppressObservers) {
+      queueTreeMutationRecord(this, nodesImpl, [], previousChildImpl, childImpl);
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-append
+  _append(nodeImpl) {
+    return this._preInsert(nodeImpl, null);
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-replace
+  _replace(nodeImpl, childImpl) {
+    const { nodeType, nodeName } = nodeImpl;
+    const { nodeType: parentType, nodeName: parentName } = this;
+
+    // Note: This section differs from the pre-insert validation algorithm.
+    if (
+      parentType !== NODE_TYPE.DOCUMENT_NODE &&
+      parentType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+      parentType !== NODE_TYPE.ELEMENT_NODE
+    ) {
+      throw DOMException.create(this._globalObject, [
+        `Node can't be inserted in a ${parentName} parent.`,
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (isHostInclusiveAncestor(nodeImpl, this)) {
+      throw DOMException.create(this._globalObject, [
+        "The operation would yield an incorrect node tree.",
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (childImpl && domSymbolTree.parent(childImpl) !== this) {
+      throw DOMException.create(this._globalObject, [
+        "The child can not be found in the parent.",
+        "NotFoundError"
+      ]);
+    }
+
+    if (
+      nodeType !== NODE_TYPE.DOCUMENT_FRAGMENT_NODE &&
+      nodeType !== NODE_TYPE.DOCUMENT_TYPE_NODE &&
+      nodeType !== NODE_TYPE.ELEMENT_NODE &&
+      nodeType !== NODE_TYPE.TEXT_NODE &&
+      nodeType !== NODE_TYPE.CDATA_SECTION_NODE && // CData section extends from Text
+      nodeType !== NODE_TYPE.PROCESSING_INSTRUCTION_NODE &&
+      nodeType !== NODE_TYPE.COMMENT_NODE
+    ) {
+      throw DOMException.create(this._globalObject, [
+        `${nodeName} node can't be inserted in parent node.`,
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (
+      (nodeType === NODE_TYPE.TEXT_NODE && parentType === NODE_TYPE.DOCUMENT_NODE) ||
+      (nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE && parentType !== NODE_TYPE.DOCUMENT_NODE)
+    ) {
+      throw DOMException.create(this._globalObject, [
+        `${nodeName} node can't be inserted in ${parentName} parent.`,
+        "HierarchyRequestError"
+      ]);
+    }
+
+    if (parentType === NODE_TYPE.DOCUMENT_NODE) {
+      const nodeChildren = domSymbolTree.childrenToArray(nodeImpl);
+      const parentChildren = domSymbolTree.childrenToArray(this);
+
+      switch (nodeType) {
+        case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: {
+          const nodeChildrenElements = nodeChildren.filter(child => child.nodeType === NODE_TYPE.ELEMENT_NODE);
+          if (nodeChildrenElements.length > 1) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+
+          const hasNodeTextChildren = nodeChildren.some(child => child.nodeType === NODE_TYPE.TEXT_NODE);
+          if (hasNodeTextChildren) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+
+
+          const parentChildElements = parentChildren.filter(child => child.nodeType === NODE_TYPE.ELEMENT_NODE);
+          if (
+            nodeChildrenElements.length === 1 &&
+            (
+              (parentChildElements.length === 1 && parentChildElements[0] !== childImpl) ||
+              (
+                childImpl &&
+                domSymbolTree.nextSibling(childImpl) &&
+                domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+              )
+            )
+          ) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+          break;
+        }
+
+        case NODE_TYPE.ELEMENT_NODE:
+          if (
+            parentChildren.some(child => child.nodeType === NODE_TYPE.ELEMENT_NODE && child !== childImpl) ||
+            (
+              childImpl &&
+              domSymbolTree.nextSibling(childImpl) &&
+              domSymbolTree.nextSibling(childImpl).nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE
+            )
+          ) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+          break;
+
+        case NODE_TYPE.DOCUMENT_TYPE_NODE:
+          if (
+            parentChildren.some(child => child.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE && child !== childImpl) ||
+            (
+              childImpl &&
+              domSymbolTree.previousSibling(childImpl) &&
+              domSymbolTree.previousSibling(childImpl).nodeType === NODE_TYPE.ELEMENT_NODE
+            )
+          ) {
+            throw DOMException.create(this._globalObject, [
+              `Invalid insertion of ${nodeName} node in ${parentName} node.`,
+              "HierarchyRequestError"
+            ]);
+          }
+          break;
+      }
+    }
+
+    let referenceChildImpl = domSymbolTree.nextSibling(childImpl);
+    if (referenceChildImpl === nodeImpl) {
+      referenceChildImpl = domSymbolTree.nextSibling(nodeImpl);
+    }
+
+    const previousSiblingImpl = domSymbolTree.previousSibling(childImpl);
+
+    this._ownerDocument._adoptNode(nodeImpl);
+
+    let removedNodesImpl = [];
+
+    if (domSymbolTree.parent(childImpl)) {
+      removedNodesImpl = [childImpl];
+      this._remove(childImpl, true);
+    }
+
+    const nodesImpl = nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ?
+      domSymbolTree.childrenToArray(nodeImpl) :
+      [nodeImpl];
+
+    this._insert(nodeImpl, referenceChildImpl, true);
+
+    queueTreeMutationRecord(this, nodesImpl, removedNodesImpl, previousSiblingImpl, referenceChildImpl);
+
+    return childImpl;
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-replace-all
+  _replaceAll(nodeImpl) {
+    if (nodeImpl !== null) {
+      this._ownerDocument._adoptNode(nodeImpl);
+    }
+
+    const removedNodesImpl = domSymbolTree.childrenToArray(this);
+
+    let addedNodesImpl;
+    if (nodeImpl === null) {
+      addedNodesImpl = [];
+    } else if (nodeImpl.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) {
+      addedNodesImpl = domSymbolTree.childrenToArray(nodeImpl);
+    } else {
+      addedNodesImpl = [nodeImpl];
+    }
+
+    for (const childImpl of domSymbolTree.childrenIterator(this)) {
+      this._remove(childImpl, true);
+    }
+
+    if (nodeImpl !== null) {
+      this._insert(nodeImpl, null, true);
+    }
+
+    if (addedNodesImpl.length > 0 || removedNodesImpl.length > 0) {
+      queueTreeMutationRecord(this, addedNodesImpl, removedNodesImpl, null, null);
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-pre-remove
+  _preRemove(childImpl) {
+    if (domSymbolTree.parent(childImpl) !== this) {
+      throw DOMException.create(this._globalObject, [
+        "The node to be removed is not a child of this node.",
+        "NotFoundError"
+      ]);
+    }
+
+    this._remove(childImpl);
+
+    return childImpl;
+  }
+
+  // https://dom.spec.whatwg.org/#concept-node-remove
+  _remove(nodeImpl, suppressObservers) {
+    const index = domSymbolTree.index(nodeImpl);
+
+    for (const descendant of domSymbolTree.treeIterator(nodeImpl)) {
+      for (const range of descendant._referencedRanges) {
+        const { _start, _end } = range;
+
+        if (_start.node === descendant) {
+          range._setLiveRangeStart(this, index);
+        }
+
+        if (_end.node === descendant) {
+          range._setLiveRangeEnd(this, index);
+        }
+      }
+    }
+
+    for (const range of this._referencedRanges) {
+      const { _start, _end } = range;
+
+      if (_start.node === this && _start.offset > index) {
+        range._setLiveRangeStart(this, _start.offset - 1);
+      }
+
+      if (_end.node === this && _end.offset > index) {
+        range._setLiveRangeEnd(this, _end.offset - 1);
+      }
+    }
+
+    if (this._ownerDocument) {
+      this._ownerDocument._runPreRemovingSteps(nodeImpl);
+    }
+
+    const oldPreviousSiblingImpl = domSymbolTree.previousSibling(nodeImpl);
+    const oldNextSiblingImpl = domSymbolTree.nextSibling(nodeImpl);
+
+    domSymbolTree.remove(nodeImpl);
+
+    if (nodeImpl._assignedSlot) {
+      assignSlotable(nodeImpl._assignedSlot);
+    }
+
+    if (isSlot(this) && this._assignedNodes.length === 0 && isShadowRoot(nodeRoot(this))) {
+      signalSlotChange(this);
+    }
+
+    let hasSlotDescendant = isSlot(nodeImpl);
+    if (!hasSlotDescendant) {
+      for (const child of domSymbolTree.treeIterator(nodeImpl)) {
+        if (isSlot(child)) {
+          hasSlotDescendant = true;
+          break;
+        }
+      }
+    }
+
+    if (hasSlotDescendant) {
+      assignSlotableForTree(nodeRoot(this));
+      assignSlotableForTree(nodeImpl);
+    }
+
+    this._modified();
+    nodeImpl._detach();
+    this._descendantRemoved(this, nodeImpl);
+
+    if (this.isConnected) {
+      if (nodeImpl._ceState === "custom") {
+        enqueueCECallbackReaction(nodeImpl, "disconnectedCallback", []);
+      }
+
+      for (const descendantImpl of shadowIncludingDescendantsIterator(nodeImpl)) {
+        if (descendantImpl._ceState === "custom") {
+          enqueueCECallbackReaction(descendantImpl, "disconnectedCallback", []);
+        }
+      }
+    }
+
+    if (!suppressObservers) {
+      queueTreeMutationRecord(this, [], [nodeImpl], oldPreviousSiblingImpl, oldNextSiblingImpl);
+    }
+
+    if (nodeImpl.nodeType === NODE_TYPE.TEXT_NODE) {
+      this._childTextContentChangeSteps();
+    }
+  }
+}
+
+module.exports = {
+  implementation: NodeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/NodeList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+"use strict";
+
+const idlUtils = require("../generated/utils.js");
+
+exports.implementation = class NodeListImpl {
+  constructor(globalObject, args, privateData) {
+    if (privateData.nodes) {
+      this._list = [...privateData.nodes];
+      this._isLive = false;
+    } else {
+      this._list = [];
+      this._isLive = true;
+      this._version = -1;
+      this._element = privateData.element;
+      this._query = privateData.query;
+      this._update();
+    }
+  }
+  get length() {
+    this._update();
+    return this._list.length;
+  }
+  item(index) {
+    this._update();
+    return this._list[index] || null;
+  }
+  _update() {
+    if (this._isLive) {
+      if (this._version < this._element._version) {
+        const snapshot = this._query();
+        for (let i = 0; i < snapshot.length; i++) {
+          this._list[i] = snapshot[i];
+        }
+        this._list.length = snapshot.length;
+        this._version = this._element._version;
+      }
+    }
+  }
+  get [idlUtils.supportedPropertyIndices]() {
+    this._update();
+    return this._list.keys();
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/NonDocumentTypeChildNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,28 @@
+"use strict";
+
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+
+class NonDocumentTypeChildNodeImpl {
+  get nextElementSibling() {
+    for (const sibling of domSymbolTree.nextSiblingsIterator(this)) {
+      if (sibling.nodeType === NODE_TYPE.ELEMENT_NODE) {
+        return sibling;
+      }
+    }
+    return null;
+  }
+
+  get previousElementSibling() {
+    for (const sibling of domSymbolTree.previousSiblingsIterator(this)) {
+      if (sibling.nodeType === NODE_TYPE.ELEMENT_NODE) {
+        return sibling;
+      }
+    }
+    return null;
+  }
+}
+
+module.exports = {
+  implementation: NonDocumentTypeChildNodeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/NonElementParentNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,11 @@
+"use strict";
+
+// https://dom.spec.whatwg.org/#interface-nonelementparentnode
+// getElementById is implemented separately inside Document and DocumentFragment.
+class NonElementParentNodeImpl {
+
+}
+
+module.exports = {
+  implementation: NonElementParentNodeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/ParentNode-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,91 @@
+"use strict";
+
+const idlUtils = require("../generated/utils");
+const NodeList = require("../generated/NodeList");
+const HTMLCollection = require("../generated/HTMLCollection");
+const { addNwsapi } = require("../helpers/selectors");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const NODE_TYPE = require("../node-type");
+const { convertNodesIntoNode } = require("../node");
+
+class ParentNodeImpl {
+  get children() {
+    if (!this._childrenList) {
+      this._childrenList = HTMLCollection.createImpl(this._globalObject, [], {
+        element: this,
+        query: () => domSymbolTree.childrenToArray(this, {
+          filter: node => node.nodeType === NODE_TYPE.ELEMENT_NODE
+        })
+      });
+    } else {
+      this._childrenList._update();
+    }
+    return this._childrenList;
+  }
+
+  get firstElementChild() {
+    for (const child of domSymbolTree.childrenIterator(this)) {
+      if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+        return child;
+      }
+    }
+
+    return null;
+  }
+
+  get lastElementChild() {
+    for (const child of domSymbolTree.childrenIterator(this, { reverse: true })) {
+      if (child.nodeType === NODE_TYPE.ELEMENT_NODE) {
+        return child;
+      }
+    }
+
+    return null;
+  }
+
+  get childElementCount() {
+    return this.children.length;
+  }
+
+  prepend(...nodes) {
+    this._preInsert(convertNodesIntoNode(this._ownerDocument, nodes), this.firstChild);
+  }
+
+  append(...nodes) {
+    this._append(convertNodesIntoNode(this._ownerDocument, nodes));
+  }
+
+  replaceChildren(...nodes) {
+    const node = convertNodesIntoNode(this._ownerDocument, nodes);
+    this._preInsertValidity(node, null);
+    this._replaceAll(node);
+  }
+
+  querySelector(selectors) {
+    if (shouldAlwaysSelectNothing(this)) {
+      return null;
+    }
+    const matcher = addNwsapi(this);
+    return idlUtils.implForWrapper(matcher.first(selectors, idlUtils.wrapperForImpl(this)));
+  }
+
+  // Warning for internal users: this returns a NodeList containing IDL wrappers instead of impls
+  querySelectorAll(selectors) {
+    if (shouldAlwaysSelectNothing(this)) {
+      return NodeList.create(this._globalObject, [], { nodes: [] });
+    }
+    const matcher = addNwsapi(this);
+    const list = matcher.select(selectors, idlUtils.wrapperForImpl(this));
+
+    return NodeList.create(this._globalObject, [], { nodes: list.map(n => idlUtils.tryImplForWrapper(n)) });
+  }
+}
+
+function shouldAlwaysSelectNothing(elImpl) {
+  // This is true during initialization.
+  return elImpl === elImpl._ownerDocument && !elImpl.documentElement;
+}
+
+module.exports = {
+  implementation: ParentNodeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/ProcessingInstruction-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,22 @@
+"use strict";
+
+const CharacterDataImpl = require("./CharacterData-impl").implementation;
+
+const NODE_TYPE = require("../node-type");
+
+class ProcessingInstructionImpl extends CharacterDataImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this.nodeType = NODE_TYPE.PROCESSING_INSTRUCTION_NODE;
+    this._target = privateData.target;
+  }
+
+  get target() {
+    return this._target;
+  }
+}
+
+module.exports = {
+  implementation: ProcessingInstructionImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,64 @@
+"use strict";
+
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { SVG_NS } = require("../helpers/namespaces");
+const { mixin } = require("../../utils");
+const SVGAnimatedString = require("../generated/SVGAnimatedString");
+const ElementImpl = require("./Element-impl").implementation;
+const ElementCSSInlineStyleImpl = require("./ElementCSSInlineStyle-impl").implementation;
+const GlobalEventHandlersImpl = require("./GlobalEventHandlers-impl").implementation;
+const HTMLOrSVGElementImpl = require("./HTMLOrSVGElement-impl").implementation;
+
+class SVGElementImpl extends ElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._initHTMLOrSVGElement();
+    this._initElementCSSInlineStyle();
+    this._initGlobalEvents();
+  }
+
+  // Keep in sync with HTMLElement. https://github.com/jsdom/jsdom/issues/2599
+  _attrModified(name, value, oldValue) {
+    if (name === "style" && value !== oldValue && !this._settingCssText) {
+      this._settingCssText = true;
+      this._style.cssText = value;
+      this._settingCssText = false;
+    } else if (name.startsWith("on")) {
+      this._globalEventChanged(name.substring(2));
+    }
+
+    super._attrModified(name, value, oldValue);
+  }
+
+  get className() {
+    return SVGAnimatedString.createImpl(this._globalObject, [], {
+      element: this,
+      attribute: "class"
+    });
+  }
+
+  get ownerSVGElement() {
+    let e = domSymbolTree.parent(this);
+    while (e && e.namespaceURI === SVG_NS) {
+      if (e.localName === "svg") {
+        return e;
+      }
+      e = domSymbolTree.parent(e);
+    }
+
+    return null;
+  }
+
+  get viewportElement() {
+    // TODO: <symbol>/<use> may make this different from ownerSVGElement.
+    return this.ownerSVGElement;
+  }
+}
+
+SVGElementImpl.attributeRegistry = new Map();
+
+mixin(SVGElementImpl.prototype, ElementCSSInlineStyleImpl.prototype);
+mixin(SVGElementImpl.prototype, GlobalEventHandlersImpl.prototype);
+mixin(SVGElementImpl.prototype, HTMLOrSVGElementImpl.prototype);
+
+exports.implementation = SVGElementImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGGraphicsElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const SVGElementImpl = require("./SVGElement-impl").implementation;
+const SVGTestsImpl = require("./SVGTests-impl").implementation;
+
+class SVGGraphicsElementImpl extends SVGElementImpl {}
+
+SVGGraphicsElementImpl.attributeRegistry = new Map([
+  ...SVGElementImpl.attributeRegistry,
+  ...SVGTestsImpl.attributeRegistry
+]);
+
+mixin(SVGGraphicsElementImpl.prototype, SVGTestsImpl.prototype);
+
+exports.implementation = SVGGraphicsElementImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGSVGElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,42 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const SVGNumber = require("../generated/SVGNumber");
+const SVGGraphicsElementImpl = require("./SVGGraphicsElement-impl").implementation;
+const WindowEventHandlersImpl = require("./WindowEventHandlers-impl").implementation;
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { ELEMENT_NODE } = require("../node-type");
+
+class SVGSVGElementImpl extends SVGGraphicsElementImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+    this._proxyWindowEventsToWindow();
+  }
+
+  createSVGNumber() {
+    return SVGNumber.createImpl(this._globalObject, [], {});
+  }
+
+  getElementById(elementId) {
+    // TODO: optimize with _ids caching trick; see Document class.
+    for (const node of domSymbolTree.treeIterator(this)) {
+      if (node.nodeType === ELEMENT_NODE && node.getAttributeNS(null, "id") === elementId) {
+        return node;
+      }
+    }
+    return null;
+  }
+
+  suspendRedraw() {
+    return 1;
+  }
+  unsuspendRedraw() {}
+  unsuspendRedrawAll() {}
+  forceRedraw() {}
+}
+
+mixin(SVGSVGElementImpl.prototype, WindowEventHandlersImpl.prototype);
+
+module.exports = {
+  implementation: SVGSVGElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGTests-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,42 @@
+"use strict";
+
+const { splitOnASCIIWhitespace, splitOnCommas } = require("../helpers/strings");
+const { reserializeCommaSeparatedTokens, reserializeSpaceSeparatedTokens } = require("../helpers/svg/basic-types");
+const SVGStringList = require("../generated/SVGStringList");
+
+class SVGTestsImpl {
+  get requiredExtensions() {
+    return SVGStringList.createImpl(this._globalObject, [], {
+      element: this,
+      attribute: "requiredExtensions"
+    });
+  }
+
+  get systemLanguage() {
+    return SVGStringList.createImpl(this._globalObject, [], {
+      element: this,
+      attribute: "systemLanguage"
+    });
+  }
+}
+
+SVGTestsImpl.attributeRegistry = new Map([
+  // https://svgwg.org/svg2-draft/struct.html#RequiredExtensionsAttribute
+  [
+    "requiredExtensions", {
+      getValue: splitOnASCIIWhitespace,
+      serialize: reserializeSpaceSeparatedTokens,
+      initialValue: undefined
+    }
+  ],
+  // https://svgwg.org/svg2-draft/struct.html#SystemLanguageAttribute
+  [
+    "systemLanguage", {
+      getValue: splitOnCommas,
+      serialize: reserializeCommaSeparatedTokens,
+      initialValue: undefined
+    }
+  ]
+]);
+
+exports.implementation = SVGTestsImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/SVGTitleElement-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+const SVGElementImpl = require("./SVGElement-impl").implementation;
+
+class SVGTitleElementImpl extends SVGElementImpl { }
+
+module.exports = {
+  implementation: SVGTitleElementImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/ShadowRoot-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,40 @@
+"use strict";
+
+const { nodeRoot } = require("../helpers/node");
+const { mixin } = require("../../utils");
+
+const DocumentFragment = require("./DocumentFragment-impl").implementation;
+const DocumentOrShadowRootImpl = require("./DocumentOrShadowRoot-impl").implementation;
+const InnerHTMLImpl = require("../domparsing/InnerHTML-impl").implementation;
+
+class ShadowRootImpl extends DocumentFragment {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    const { mode } = privateData;
+    this._mode = mode;
+  }
+
+  _getTheParent(event) {
+    if (!event.composed && this === nodeRoot(event._path[0].item)) {
+      return null;
+    }
+
+    return this._host;
+  }
+
+  get mode() {
+    return this._mode;
+  }
+
+  get host() {
+    return this._host;
+  }
+}
+
+mixin(ShadowRootImpl.prototype, DocumentOrShadowRootImpl.prototype);
+mixin(ShadowRootImpl.prototype, InnerHTMLImpl.prototype);
+
+module.exports = {
+  implementation: ShadowRootImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/Slotable-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+"use strict";
+
+const { findSlot, assignSlot, assignSlotable } = require("../helpers/shadow-dom");
+
+// https://dom.spec.whatwg.org/#mixin-slotable
+// https://dom.spec.whatwg.org/#light-tree-slotables
+class SlotableMixinImpl {
+  _initSlotableMixin() {
+    this._slotableName = "";
+  }
+
+  _attrModifiedSlotableMixin(name, value, oldValue) {
+    if (name === "slot") {
+      if (value === oldValue) {
+        return;
+      }
+
+      if (value === null && oldValue === "") {
+        return;
+      }
+
+      if (value === "" && oldValue === null) {
+        return;
+      }
+
+      if (value === null || value === "") {
+        this._slotableName = "";
+      } else {
+        this._slotableName = value;
+      }
+
+
+      if (this._assignedSlot) {
+        assignSlotable(this._assignedSlot);
+      }
+
+      assignSlot(this);
+    }
+  }
+
+  get assignedSlot() {
+    return findSlot(this, "open");
+  }
+}
+
+module.exports = {
+  implementation: SlotableMixinImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/Text-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,96 @@
+"use strict";
+const SlotableMixinImpl = require("./Slotable-impl").implementation;
+const CharacterDataImpl = require("./CharacterData-impl").implementation;
+const idlUtils = require("../generated/utils");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const DOMException = require("domexception/webidl2js-wrapper");
+const NODE_TYPE = require("../node-type");
+const { mixin } = require("../../utils");
+
+// https://dom.spec.whatwg.org/#text
+class TextImpl extends CharacterDataImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, {
+      data: args[0],
+      ownerDocument: idlUtils.implForWrapper(globalObject._document),
+      ...privateData
+    });
+
+    this._initSlotableMixin();
+
+    this.nodeType = NODE_TYPE.TEXT_NODE;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-text-splittext
+  // https://dom.spec.whatwg.org/#concept-text-split
+  splitText(offset) {
+    const { length } = this;
+
+    if (offset > length) {
+      throw DOMException.create(this._globalObject, ["The index is not in the allowed range.", "IndexSizeError"]);
+    }
+
+    const count = length - offset;
+    const newData = this.substringData(offset, count);
+
+    const newNode = this._ownerDocument.createTextNode(newData);
+
+    const parent = domSymbolTree.parent(this);
+
+    if (parent !== null) {
+      parent._insert(newNode, this.nextSibling);
+
+      for (const range of this._referencedRanges) {
+        const { _start, _end } = range;
+
+        if (_start.node === this && _start.offset > offset) {
+          range._setLiveRangeStart(newNode, _start.offset - offset);
+        }
+
+        if (_end.node === this && _end.offset > offset) {
+          range._setLiveRangeEnd(newNode, _end.offset - offset);
+        }
+      }
+
+      const nodeIndex = domSymbolTree.index(this);
+      for (const range of parent._referencedRanges) {
+        const { _start, _end } = range;
+
+        if (_start.node === parent && _start.offset === nodeIndex + 1) {
+          range._setLiveRangeStart(parent, _start.offset + 1);
+        }
+
+        if (_end.node === parent && _end.offset === nodeIndex + 1) {
+          range._setLiveRangeEnd(parent, _end.offset + 1);
+        }
+      }
+    }
+
+    this.replaceData(offset, count, "");
+
+    return newNode;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-text-wholetext
+  get wholeText() {
+    let wholeText = this.textContent;
+    let next;
+    let current = this;
+    while ((next = domSymbolTree.previousSibling(current)) && next.nodeType === NODE_TYPE.TEXT_NODE) {
+      wholeText = next.textContent + wholeText;
+      current = next;
+    }
+    current = this;
+    while ((next = domSymbolTree.nextSibling(current)) && next.nodeType === NODE_TYPE.TEXT_NODE) {
+      wholeText += next.textContent;
+      current = next;
+    }
+    return wholeText;
+  }
+}
+
+mixin(TextImpl.prototype, SlotableMixinImpl.prototype);
+
+module.exports = {
+  implementation: TextImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/WindowEventHandlers-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,52 @@
+"use strict";
+
+const { createEventAccessor } = require("../helpers/create-event-accessor");
+
+const events = new Set([
+  // WindowEventHandlers
+  "afterprint",
+  "beforeprint",
+  "beforeunload",
+  "hashchange",
+  "languagechange",
+  "message",
+  "messageerror",
+  "offline",
+  "online",
+  "pagehide",
+  "pageshow",
+  "popstate",
+  "rejectionhandled",
+  "storage",
+  "unhandledrejection",
+  "unload",
+
+  // inherited and overridden
+  "blur",
+  "error",
+  "focus",
+  "load",
+  "resize",
+  "scroll"
+]);
+
+// This class builds on GlobalEventHandlers, which must be mixed in first.
+class WindowEventHandlersImpl {
+  _proxyWindowEventsToWindow() {
+    // We're a <body> or <frameset>, so we need to proxy these specific events to the Window (if it exists)
+    this._getEventHandlerTarget = event => {
+      if (events.has(event)) {
+        return this.ownerDocument.defaultView || null;
+      }
+      return this;
+    };
+  }
+}
+
+for (const event of events) {
+  createEventAccessor(WindowEventHandlersImpl.prototype, event);
+}
+
+module.exports = {
+  implementation: WindowEventHandlersImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/nodes/XMLDocument-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,4 @@
+"use strict";
+const DocumentImpl = require("./Document-impl").implementation;
+
+exports.implementation = class XMLDocumentImpl extends DocumentImpl {};
Index: frontend/node_modules/jsdom/lib/jsdom/living/post-message.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/post-message.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/post-message.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,39 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const MessageEvent = require("./generated/MessageEvent");
+const idlUtils = require("./generated/utils");
+const { isValidTargetOrigin } = require("../utils");
+const { fireAnEvent } = require("./helpers/events");
+
+module.exports = function (globalObject) {
+  return function (message, targetOrigin) {
+    if (arguments.length < 2) {
+      throw new TypeError("'postMessage' requires 2 arguments: 'message' and 'targetOrigin'");
+    }
+
+    targetOrigin = String(targetOrigin);
+
+    if (!isValidTargetOrigin(targetOrigin)) {
+      // TODO: Fix me
+      throw DOMException.create(globalObject, [
+        "Failed to execute 'postMessage' on 'Window': " +
+        "Invalid target origin '" + targetOrigin + "' in a call to 'postMessage'.",
+        "SyntaxError"
+      ]);
+    }
+
+    // TODO: targetOrigin === '/' - requires reference to source window
+    // See https://github.com/jsdom/jsdom/pull/1140#issuecomment-111587499
+    if (targetOrigin !== "*" && targetOrigin !== idlUtils.implForWrapper(globalObject._document)._origin) {
+      return;
+    }
+
+    // TODO: event.source - requires reference to source window
+    // TODO: event.origin - requires reference to source window
+    // TODO: event.ports
+    // TODO: event.data - structured clone message - requires cloning DOM nodes
+    setTimeout(() => {
+      fireAnEvent("message", this, MessageEvent, { data: message });
+    }, 0);
+  };
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/range/AbstractRange-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/range/AbstractRange-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/range/AbstractRange-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,43 @@
+"use strict";
+
+// https://dom.spec.whatwg.org/#abstractrange
+class AbstractRangeImpl {
+  constructor(globalObject, args, privateData) {
+    const { start, end } = privateData;
+
+    this._start = start;
+    this._end = end;
+
+    this._globalObject = globalObject;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-startcontainer
+  get startContainer() {
+    return this._start.node;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-startoffset
+  get startOffset() {
+    return this._start.offset;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-endcontainer
+  get endContainer() {
+    return this._end.node;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-endoffset
+  get endOffset() {
+    return this._end.offset;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-collapsed
+  get collapsed() {
+    const { _start, _end } = this;
+    return _start.node === _end.node && _start.offset === _end.offset;
+  }
+}
+
+module.exports = {
+  implementation: AbstractRangeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/range/Range-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/range/Range-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/range/Range-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,889 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const { clone } = require("../node");
+const NODE_TYPE = require("../node-type");
+const { parseFragment } = require("../../browser/parser/index");
+
+const { HTML_NS } = require("../helpers/namespaces");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { compareBoundaryPointsPosition } = require("./boundary-point");
+const { nodeRoot, nodeLength, isInclusiveAncestor } = require("../helpers/node");
+const { createElement } = require("../helpers/create-element");
+
+const AbstractRangeImpl = require("./AbstractRange-impl").implementation;
+
+const Range = require("../generated/Range");
+const DocumentFragment = require("../generated/DocumentFragment");
+const { implForWrapper } = require("../generated/utils");
+
+const RANGE_COMPARISON_TYPE = {
+  START_TO_START: 0,
+  START_TO_END: 1,
+  END_TO_END: 2,
+  END_TO_START: 3
+};
+
+class RangeImpl extends AbstractRangeImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    const defaultBoundaryPoint = {
+      node: implForWrapper(globalObject._document),
+      offset: 0
+    };
+
+    const {
+      start = defaultBoundaryPoint,
+      end = defaultBoundaryPoint
+    } = privateData;
+
+    this._setLiveRangeStart(start.node, start.offset);
+    this._setLiveRangeEnd(end.node, end.offset);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-commonancestorcontainer
+  get commonAncestorContainer() {
+    const { _start, _end } = this;
+
+    for (const container of domSymbolTree.ancestorsIterator(_start.node)) {
+      if (isInclusiveAncestor(container, _end.node)) {
+        return container;
+      }
+    }
+
+    return null;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-setstart
+  setStart(node, offset) {
+    setBoundaryPointStart(this, node, offset);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-setend
+  setEnd(node, offset) {
+    setBoundaryPointEnd(this, node, offset);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-setstartbefore
+  setStartBefore(node) {
+    const parent = domSymbolTree.parent(node);
+
+    if (!parent) {
+      throw DOMException.create(this._globalObject, ["The given Node has no parent.", "InvalidNodeTypeError"]);
+    }
+
+    setBoundaryPointStart(this, parent, domSymbolTree.index(node));
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-setstartafter
+  setStartAfter(node) {
+    const parent = domSymbolTree.parent(node);
+
+    if (!parent) {
+      throw DOMException.create(this._globalObject, ["The given Node has no parent.", "InvalidNodeTypeError"]);
+    }
+
+    setBoundaryPointStart(this, parent, domSymbolTree.index(node) + 1);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-setendbefore
+  setEndBefore(node) {
+    const parent = domSymbolTree.parent(node);
+
+    if (!parent) {
+      throw DOMException.create(this._globalObject, ["The given Node has no parent.", "InvalidNodeTypeError"]);
+    }
+
+    setBoundaryPointEnd(this, parent, domSymbolTree.index(node));
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-setendafter
+  setEndAfter(node) {
+    const parent = domSymbolTree.parent(node);
+
+    if (!parent) {
+      throw DOMException.create(this._globalObject, ["The given Node has no parent.", "InvalidNodeTypeError"]);
+    }
+
+    setBoundaryPointEnd(this, parent, domSymbolTree.index(node) + 1);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-collapse
+  collapse(toStart) {
+    if (toStart) {
+      this._setLiveRangeEnd(this._start.node, this._start.offset);
+    } else {
+      this._setLiveRangeStart(this._end.node, this._end.offset);
+    }
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-selectnode
+  selectNode(node) {
+    selectNodeWithinRange(node, this);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-selectnodecontents
+  selectNodeContents(node) {
+    if (node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
+      throw DOMException.create(this._globalObject, [
+        "DocumentType Node can't be used as boundary point.",
+        "InvalidNodeTypeError"
+      ]);
+    }
+
+    const length = nodeLength(node);
+
+    this._setLiveRangeStart(node, 0);
+    this._setLiveRangeEnd(node, length);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-compareboundarypoints
+  compareBoundaryPoints(how, sourceRange) {
+    if (
+      how !== RANGE_COMPARISON_TYPE.START_TO_START &&
+      how !== RANGE_COMPARISON_TYPE.START_TO_END &&
+      how !== RANGE_COMPARISON_TYPE.END_TO_END &&
+      how !== RANGE_COMPARISON_TYPE.END_TO_START
+    ) {
+      const message = "The comparison method provided must be one of 'START_TO_START', 'START_TO_END', 'END_TO_END', " +
+                      "or 'END_TO_START'.";
+      throw DOMException.create(this._globalObject, [message, "NotSupportedError"]);
+    }
+
+    if (this._root !== sourceRange._root) {
+      throw DOMException.create(this._globalObject, ["The two Ranges are not in the same tree.", "WrongDocumentError"]);
+    }
+
+    let thisPoint, otherPoint;
+    if (how === RANGE_COMPARISON_TYPE.START_TO_START) {
+      thisPoint = this._start;
+      otherPoint = sourceRange._start;
+    } else if (how === RANGE_COMPARISON_TYPE.START_TO_END) {
+      thisPoint = this._end;
+      otherPoint = sourceRange._start;
+    } else if (how === RANGE_COMPARISON_TYPE.END_TO_END) {
+      thisPoint = this._end;
+      otherPoint = sourceRange._end;
+    } else {
+      thisPoint = this._start;
+      otherPoint = sourceRange._end;
+    }
+
+    return compareBoundaryPointsPosition(thisPoint, otherPoint);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-deletecontents
+  deleteContents() {
+    if (this.collapsed) {
+      return;
+    }
+
+    const { _start: originalStart, _end: originalEnd } = this;
+
+    if (
+      originalStart.node === originalEnd.node &&
+      (
+        originalStart.node.nodeType === NODE_TYPE.TEXT_NODE ||
+        originalStart.node.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+        originalStart.node.nodeType === NODE_TYPE.COMMENT_NODE
+      )
+    ) {
+      originalStart.node.replaceData(originalStart.offset, originalEnd.offset - originalStart.offset, "");
+      return;
+    }
+
+    const nodesToRemove = [];
+    let currentNode = this._start.node;
+    const endNode = nextNodeDescendant(this._end.node);
+    while (currentNode && currentNode !== endNode) {
+      if (
+        isContained(currentNode, this) &&
+        !isContained(domSymbolTree.parent(currentNode), this)
+      ) {
+        nodesToRemove.push(currentNode);
+      }
+
+      currentNode = domSymbolTree.following(currentNode);
+    }
+
+    let newNode, newOffset;
+    if (isInclusiveAncestor(originalStart.node, originalEnd.node)) {
+      newNode = originalStart.node;
+      newOffset = originalStart.offset;
+    } else {
+      let referenceNode = originalStart.node;
+
+      while (
+        referenceNode &&
+        !isInclusiveAncestor(domSymbolTree.parent(referenceNode), originalEnd.node)
+      ) {
+        referenceNode = domSymbolTree.parent(referenceNode);
+      }
+
+      newNode = domSymbolTree.parent(referenceNode);
+      newOffset = domSymbolTree.index(referenceNode) + 1;
+    }
+
+    if (
+      originalStart.node.nodeType === NODE_TYPE.TEXT_NODE ||
+      originalStart.node.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      originalStart.node.nodeType === NODE_TYPE.COMMENT_NODE
+    ) {
+      originalStart.node.replaceData(originalStart.offset, nodeLength(originalStart.node) - originalStart.offset, "");
+    }
+
+    for (const node of nodesToRemove) {
+      const parent = domSymbolTree.parent(node);
+      parent.removeChild(node);
+    }
+
+    if (
+      originalEnd.node.nodeType === NODE_TYPE.TEXT_NODE ||
+      originalEnd.node.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      originalEnd.node.nodeType === NODE_TYPE.COMMENT_NODE
+    ) {
+      originalEnd.node.replaceData(0, originalEnd.offset, "");
+    }
+
+    this._setLiveRangeStart(newNode, newOffset);
+    this._setLiveRangeEnd(newNode, newOffset);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-extractcontents
+  extractContents() {
+    return extractRange(this);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-clonecontents
+  cloneContents() {
+    return cloneRange(this);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-insertnode
+  insertNode(node) {
+    insertNodeInRange(node, this);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-surroundcontents
+  surroundContents(newParent) {
+    let node = this.commonAncestorContainer;
+    const endNode = nextNodeDescendant(node);
+    while (node !== endNode) {
+      if (node.nodeType !== NODE_TYPE.TEXT_NODE && isPartiallyContained(node, this)) {
+        throw DOMException.create(this._globalObject, [
+          "The Range has partially contains a non-Text node.",
+          "InvalidStateError"
+        ]);
+      }
+
+      node = domSymbolTree.following(node);
+    }
+
+    if (
+      newParent.nodeType === NODE_TYPE.DOCUMENT_NODE ||
+      newParent.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE ||
+      newParent.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE
+    ) {
+      throw DOMException.create(this._globalObject, ["Invalid element type.", "InvalidNodeTypeError"]);
+    }
+
+    const fragment = extractRange(this);
+
+    while (domSymbolTree.firstChild(newParent)) {
+      newParent.removeChild(domSymbolTree.firstChild(newParent));
+    }
+
+    insertNodeInRange(newParent, this);
+
+    newParent.appendChild(fragment);
+
+    selectNodeWithinRange(newParent, this);
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-clonerange
+  cloneRange() {
+    const { _start, _end, _globalObject } = this;
+
+    return Range.createImpl(_globalObject, [], {
+      start: { node: _start.node, offset: _start.offset },
+      end: { node: _end.node, offset: _end.offset }
+    });
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-detach
+  detach() {
+    // Do nothing by spec!
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-ispointinrange
+  isPointInRange(node, offset) {
+    if (nodeRoot(node) !== this._root) {
+      return false;
+    }
+
+    validateSetBoundaryPoint(node, offset);
+
+    const bp = { node, offset };
+
+    if (
+      compareBoundaryPointsPosition(bp, this._start) === -1 ||
+      compareBoundaryPointsPosition(bp, this._end) === 1
+    ) {
+      return false;
+    }
+
+    return true;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-comparepoint
+  comparePoint(node, offset) {
+    if (nodeRoot(node) !== this._root) {
+      throw DOMException.create(this._globalObject, [
+        "The given Node and the Range are not in the same tree.",
+        "WrongDocumentError"
+      ]);
+    }
+
+    validateSetBoundaryPoint(node, offset);
+
+    const bp = { node, offset };
+    if (compareBoundaryPointsPosition(bp, this._start) === -1) {
+      return -1;
+    } else if (compareBoundaryPointsPosition(bp, this._end) === 1) {
+      return 1;
+    }
+
+    return 0;
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-intersectsnode
+  intersectsNode(node) {
+    if (nodeRoot(node) !== this._root) {
+      return false;
+    }
+
+    const parent = domSymbolTree.parent(node);
+    if (!parent) {
+      return true;
+    }
+
+    const offset = domSymbolTree.index(node);
+
+    return (
+      compareBoundaryPointsPosition({ node: parent, offset }, this._end) === -1 &&
+      compareBoundaryPointsPosition({ node: parent, offset: offset + 1 }, this._start) === 1
+    );
+  }
+
+  // https://dom.spec.whatwg.org/#dom-range-stringifier
+  toString() {
+    let s = "";
+    const { _start, _end } = this;
+
+    if (_start.node === _end.node && _start.node.nodeType === NODE_TYPE.TEXT_NODE) {
+      return _start.node.data.slice(_start.offset, _end.offset);
+    }
+
+    if (_start.node.nodeType === NODE_TYPE.TEXT_NODE) {
+      s += _start.node.data.slice(_start.offset);
+    }
+
+    let currentNode = _start.node;
+    const endNode = nextNodeDescendant(_end.node);
+    while (currentNode && currentNode !== endNode) {
+      if (currentNode.nodeType === NODE_TYPE.TEXT_NODE && isContained(currentNode, this)) {
+        s += currentNode.data;
+      }
+
+      currentNode = domSymbolTree.following(currentNode);
+    }
+
+    if (_end.node.nodeType === NODE_TYPE.TEXT_NODE) {
+      s += _end.node.data.slice(0, _end.offset);
+    }
+
+    return s;
+  }
+
+  // https://w3c.github.io/DOM-Parsing/#dom-range-createcontextualfragment
+  createContextualFragment(fragment) {
+    const { node } = this._start;
+
+    let element;
+    switch (node.nodeType) {
+      case NODE_TYPE.DOCUMENT_NODE:
+      case NODE_TYPE.DOCUMENT_FRAGMENT_NODE:
+        element = null;
+        break;
+
+      case NODE_TYPE.ELEMENT_NODE:
+        element = node;
+        break;
+
+      case NODE_TYPE.TEXT_NODE:
+      case NODE_TYPE.COMMENT_NODE:
+        element = node.parentElement;
+        break;
+
+      default:
+        throw new Error("Internal error: Invalid range start node");
+    }
+
+    if (
+      element === null || (
+        element._ownerDocument._parsingMode === "html" &&
+        element._localName === "html" &&
+        element._namespaceURI === HTML_NS
+      )
+    ) {
+      element = createElement(node._ownerDocument, "body", HTML_NS);
+    }
+
+    return parseFragment(fragment, element);
+  }
+
+  // https://dom.spec.whatwg.org/#concept-range-root
+  get _root() {
+    return nodeRoot(this._start.node);
+  }
+
+  _setLiveRangeStart(node, offset) {
+    if (this._start && this._start.node !== node) {
+      this._start.node._referencedRanges.delete(this);
+    }
+
+    if (!node._referencedRanges.has(this)) {
+      node._referencedRanges.add(this);
+    }
+
+    this._start = {
+      node,
+      offset
+    };
+  }
+
+  _setLiveRangeEnd(node, offset) {
+    if (this._end && this._end.node !== node) {
+      this._end.node._referencedRanges.delete(this);
+    }
+
+    if (!node._referencedRanges.has(this)) {
+      node._referencedRanges.add(this);
+    }
+
+    this._end = {
+      node,
+      offset
+    };
+  }
+}
+
+
+function nextNodeDescendant(node) {
+  while (node && !domSymbolTree.nextSibling(node)) {
+    node = domSymbolTree.parent(node);
+  }
+
+  if (!node) {
+    return null;
+  }
+
+  return domSymbolTree.nextSibling(node);
+}
+
+// https://dom.spec.whatwg.org/#concept-range-bp-set
+function validateSetBoundaryPoint(node, offset) {
+  if (node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
+    throw DOMException.create(node._globalObject, [
+      "DocumentType Node can't be used as boundary point.",
+      "InvalidNodeTypeError"
+    ]);
+  }
+
+  if (offset > nodeLength(node)) {
+    throw DOMException.create(node._globalObject, ["Offset out of bound.", "IndexSizeError"]);
+  }
+}
+function setBoundaryPointStart(range, node, offset) {
+  validateSetBoundaryPoint(node, offset);
+
+  const bp = { node, offset };
+  if (
+    nodeRoot(node) !== range._root ||
+    compareBoundaryPointsPosition(bp, range._end) === 1
+  ) {
+    range._setLiveRangeEnd(node, offset);
+  }
+
+  range._setLiveRangeStart(node, offset);
+}
+function setBoundaryPointEnd(range, node, offset) {
+  validateSetBoundaryPoint(node, offset);
+
+  const bp = { node, offset };
+  if (
+    nodeRoot(node) !== range._root ||
+    compareBoundaryPointsPosition(bp, range._start) === -1
+  ) {
+    range._setLiveRangeStart(node, offset);
+  }
+
+  range._setLiveRangeEnd(node, offset);
+}
+
+// https://dom.spec.whatwg.org/#concept-range-select
+function selectNodeWithinRange(node, range) {
+  const parent = domSymbolTree.parent(node);
+
+  if (!parent) {
+    throw DOMException.create(node._globalObject, ["The given Node has no parent.", "InvalidNodeTypeError"]);
+  }
+
+  const index = domSymbolTree.index(node);
+
+  range._setLiveRangeStart(parent, index);
+  range._setLiveRangeEnd(parent, index + 1);
+}
+
+// https://dom.spec.whatwg.org/#contained
+function isContained(node, range) {
+  const { _start, _end } = range;
+  return (
+    compareBoundaryPointsPosition({ node, offset: 0 }, _start) === 1 &&
+    compareBoundaryPointsPosition({ node, offset: nodeLength(node) }, _end) === -1
+  );
+}
+
+// https://dom.spec.whatwg.org/#partially-contained
+function isPartiallyContained(node, range) {
+  const { _start, _end } = range;
+  return (
+    (isInclusiveAncestor(node, _start.node) && !isInclusiveAncestor(node, _end.node)) ||
+    (!isInclusiveAncestor(node, _start.node) && isInclusiveAncestor(node, _end.node))
+  );
+}
+
+// https://dom.spec.whatwg.org/#concept-range-insert
+function insertNodeInRange(node, range) {
+  const { node: startNode, offset: startOffset } = range._start;
+
+  if (
+    startNode.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+    startNode.nodeType === NODE_TYPE.COMMENT_NODE ||
+    (startNode.nodeType === NODE_TYPE.TEXT_NODE && !domSymbolTree.parent(startNode)) ||
+    node === startNode
+  ) {
+    throw DOMException.create(node._globalObject, ["Invalid start node.", "HierarchyRequestError"]);
+  }
+
+  let referenceNode = startNode.nodeType === NODE_TYPE.TEXT_NODE ?
+    startNode :
+    domSymbolTree.childrenToArray(startNode)[startOffset] || null;
+  const parent = !referenceNode ?
+    startNode :
+    domSymbolTree.parent(referenceNode);
+
+  parent._preInsertValidity(node, referenceNode);
+
+  if (startNode.nodeType === NODE_TYPE.TEXT_NODE) {
+    referenceNode = startNode.splitText(startOffset);
+  }
+
+  if (node === referenceNode) {
+    referenceNode = domSymbolTree.nextSibling(referenceNode);
+  }
+
+  const nodeParent = domSymbolTree.parent(node);
+  if (nodeParent) {
+    nodeParent.removeChild(node);
+  }
+
+  let newOffset = !referenceNode ? nodeLength(parent) : domSymbolTree.index(referenceNode);
+  newOffset += node.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE ? nodeLength(node) : 1;
+
+  parent.insertBefore(node, referenceNode);
+
+  if (range.collapsed) {
+    range._setLiveRangeEnd(parent, newOffset);
+  }
+}
+
+// https://dom.spec.whatwg.org/#concept-range-clone
+function cloneRange(range) {
+  const { _start: originalStart, _end: originalEnd, _globalObject } = range;
+
+  const fragment = DocumentFragment.createImpl(_globalObject, [], {
+    ownerDocument: originalStart.node._ownerDocument
+  });
+
+  if (range.collapsed) {
+    return fragment;
+  }
+
+  if (
+    originalStart.node === originalEnd.node &&
+    (
+      originalStart.node.nodeType === NODE_TYPE.TEXT_NODE ||
+      originalStart.node.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      originalStart.node.nodeType === NODE_TYPE.COMMENT_NODE
+    )
+  ) {
+    const cloned = clone(originalStart.node);
+    cloned._data = cloned.substringData(originalStart.offset, originalEnd.offset - originalStart.offset);
+
+    fragment.appendChild(cloned);
+
+    return fragment;
+  }
+
+  let commonAncestor = originalStart.node;
+  while (!isInclusiveAncestor(commonAncestor, originalEnd.node)) {
+    commonAncestor = domSymbolTree.parent(commonAncestor);
+  }
+
+  let firstPartialContainedChild = null;
+  if (!isInclusiveAncestor(originalStart.node, originalEnd.node)) {
+    let candidate = domSymbolTree.firstChild(commonAncestor);
+    while (!firstPartialContainedChild) {
+      if (isPartiallyContained(candidate, range)) {
+        firstPartialContainedChild = candidate;
+      }
+
+      candidate = domSymbolTree.nextSibling(candidate);
+    }
+  }
+
+  let lastPartiallyContainedChild = null;
+  if (!isInclusiveAncestor(originalEnd.node, originalStart.node)) {
+    let candidate = domSymbolTree.lastChild(commonAncestor);
+    while (!lastPartiallyContainedChild) {
+      if (isPartiallyContained(candidate, range)) {
+        lastPartiallyContainedChild = candidate;
+      }
+
+      candidate = domSymbolTree.previousSibling(candidate);
+    }
+  }
+
+  const containedChildren = domSymbolTree.childrenToArray(commonAncestor)
+    .filter(node => isContained(node, range));
+
+  const hasDoctypeChildren = containedChildren.some(node => node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE);
+  if (hasDoctypeChildren) {
+    throw DOMException.create(range._globalObject, ["Invalid document type element.", "HierarchyRequestError"]);
+  }
+
+  if (
+    firstPartialContainedChild !== null &&
+    (
+      firstPartialContainedChild.nodeType === NODE_TYPE.TEXT_NODE ||
+      firstPartialContainedChild.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      firstPartialContainedChild.nodeType === NODE_TYPE.COMMENT_NODE
+    )
+  ) {
+    const cloned = clone(originalStart.node);
+    cloned._data = cloned.substringData(originalStart.offset, nodeLength(originalStart.node) - originalStart.offset);
+
+    fragment.appendChild(cloned);
+  } else if (firstPartialContainedChild !== null) {
+    const cloned = clone(firstPartialContainedChild);
+    fragment.appendChild(cloned);
+
+    const subrange = Range.createImpl(_globalObject, [], {
+      start: { node: originalStart.node, offset: originalStart.offset },
+      end: { node: firstPartialContainedChild, offset: nodeLength(firstPartialContainedChild) }
+    });
+
+    const subfragment = cloneRange(subrange);
+    cloned.appendChild(subfragment);
+  }
+
+  for (const containedChild of containedChildren) {
+    const cloned = clone(containedChild, undefined, true);
+    fragment.appendChild(cloned);
+  }
+
+  if (
+    lastPartiallyContainedChild !== null &&
+    (
+      lastPartiallyContainedChild.nodeType === NODE_TYPE.TEXT_NODE ||
+      lastPartiallyContainedChild.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      lastPartiallyContainedChild.nodeType === NODE_TYPE.COMMENT_NODE
+    )
+  ) {
+    const cloned = clone(originalEnd.node);
+    cloned._data = cloned.substringData(0, originalEnd.offset);
+
+    fragment.appendChild(cloned);
+  } else if (lastPartiallyContainedChild !== null) {
+    const cloned = clone(lastPartiallyContainedChild);
+    fragment.appendChild(cloned);
+
+    const subrange = Range.createImpl(_globalObject, [], {
+      start: { node: lastPartiallyContainedChild, offset: 0 },
+      end: { node: originalEnd.node, offset: originalEnd.offset }
+    });
+
+    const subfragment = cloneRange(subrange);
+    cloned.appendChild(subfragment);
+  }
+
+  return fragment;
+}
+
+// https://dom.spec.whatwg.org/#concept-range-extract
+function extractRange(range) {
+  const { _start: originalStart, _end: originalEnd, _globalObject } = range;
+
+  const fragment = DocumentFragment.createImpl(_globalObject, [], {
+    ownerDocument: originalStart.node._ownerDocument
+  });
+
+  if (range.collapsed) {
+    return fragment;
+  }
+
+  if (
+    originalStart.node === originalEnd.node &&
+    (
+      originalStart.node.nodeType === NODE_TYPE.TEXT_NODE ||
+      originalStart.node.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      originalStart.node.nodeType === NODE_TYPE.COMMENT_NODE
+    )
+  ) {
+    const cloned = clone(originalStart.node);
+    cloned._data = cloned.substringData(originalStart.offset, originalEnd.offset - originalStart.offset);
+
+    fragment.appendChild(cloned);
+    originalStart.node.replaceData(originalStart.offset, originalEnd.offset - originalStart.offset, "");
+
+    return fragment;
+  }
+
+  let commonAncestor = originalStart.node;
+  while (!isInclusiveAncestor(commonAncestor, originalEnd.node)) {
+    commonAncestor = domSymbolTree.parent(commonAncestor);
+  }
+
+  let firstPartialContainedChild = null;
+  if (!isInclusiveAncestor(originalStart.node, originalEnd.node)) {
+    let candidate = domSymbolTree.firstChild(commonAncestor);
+    while (!firstPartialContainedChild) {
+      if (isPartiallyContained(candidate, range)) {
+        firstPartialContainedChild = candidate;
+      }
+
+      candidate = domSymbolTree.nextSibling(candidate);
+    }
+  }
+
+  let lastPartiallyContainedChild = null;
+  if (!isInclusiveAncestor(originalEnd.node, originalStart.node)) {
+    let candidate = domSymbolTree.lastChild(commonAncestor);
+    while (!lastPartiallyContainedChild) {
+      if (isPartiallyContained(candidate, range)) {
+        lastPartiallyContainedChild = candidate;
+      }
+
+      candidate = domSymbolTree.previousSibling(candidate);
+    }
+  }
+
+  const containedChildren = domSymbolTree.childrenToArray(commonAncestor)
+    .filter(node => isContained(node, range));
+
+  const hasDoctypeChildren = containedChildren.some(node => node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE);
+  if (hasDoctypeChildren) {
+    throw DOMException.create(range._globalObject, ["Invalid document type element.", "HierarchyRequestError"]);
+  }
+
+  let newNode, newOffset;
+  if (isInclusiveAncestor(originalStart.node, originalEnd.node)) {
+    newNode = originalStart.node;
+    newOffset = originalStart.offset;
+  } else {
+    let referenceNode = originalStart.node;
+
+    while (
+      referenceNode &&
+      !isInclusiveAncestor(domSymbolTree.parent(referenceNode), originalEnd.node)
+    ) {
+      referenceNode = domSymbolTree.parent(referenceNode);
+    }
+
+    newNode = domSymbolTree.parent(referenceNode);
+    newOffset = domSymbolTree.index(referenceNode) + 1;
+  }
+
+  if (
+    firstPartialContainedChild !== null &&
+    (
+      firstPartialContainedChild.nodeType === NODE_TYPE.TEXT_NODE ||
+      firstPartialContainedChild.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      firstPartialContainedChild.nodeType === NODE_TYPE.COMMENT_NODE
+    )
+  ) {
+    const cloned = clone(originalStart.node);
+    cloned._data = cloned.substringData(originalStart.offset, nodeLength(originalStart.node) - originalStart.offset);
+
+    fragment.appendChild(cloned);
+
+    originalStart.node.replaceData(originalStart.offset, nodeLength(originalStart.node) - originalStart.offset, "");
+  } else if (firstPartialContainedChild !== null) {
+    const cloned = clone(firstPartialContainedChild);
+    fragment.appendChild(cloned);
+
+    const subrange = Range.createImpl(_globalObject, [], {
+      start: { node: originalStart.node, offset: originalStart.offset },
+      end: { node: firstPartialContainedChild, offset: nodeLength(firstPartialContainedChild) }
+    });
+
+    const subfragment = extractRange(subrange);
+    cloned.appendChild(subfragment);
+  }
+
+  for (const containedChild of containedChildren) {
+    fragment.appendChild(containedChild);
+  }
+
+  if (
+    lastPartiallyContainedChild !== null &&
+    (
+      lastPartiallyContainedChild.nodeType === NODE_TYPE.TEXT_NODE ||
+      lastPartiallyContainedChild.nodeType === NODE_TYPE.PROCESSING_INSTRUCTION_NODE ||
+      lastPartiallyContainedChild.nodeType === NODE_TYPE.COMMENT_NODE
+    )
+  ) {
+    const cloned = clone(originalEnd.node);
+    cloned._data = cloned.substringData(0, originalEnd.offset);
+
+    fragment.appendChild(cloned);
+
+    originalEnd.node.replaceData(0, originalEnd.offset, "");
+  } else if (lastPartiallyContainedChild !== null) {
+    const cloned = clone(lastPartiallyContainedChild);
+    fragment.appendChild(cloned);
+
+    const subrange = Range.createImpl(_globalObject, [], {
+      start: { node: lastPartiallyContainedChild, offset: 0 },
+      end: { node: originalEnd.node, offset: originalEnd.offset }
+    });
+
+    const subfragment = extractRange(subrange);
+    cloned.appendChild(subfragment);
+  }
+
+  range._setLiveRangeStart(newNode, newOffset);
+  range._setLiveRangeEnd(newNode, newOffset);
+
+  return fragment;
+}
+
+module.exports = {
+  implementation: RangeImpl,
+
+  setBoundaryPointStart,
+  setBoundaryPointEnd
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/range/StaticRange-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/range/StaticRange-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/range/StaticRange-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,39 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const NODE_TYPE = require("../node-type");
+
+const AbstractRangeImpl = require("./AbstractRange-impl").implementation;
+
+// https://dom.spec.whatwg.org/#staticrange
+class StaticRangeImpl extends AbstractRangeImpl {
+  // https://dom.spec.whatwg.org/#dom-staticrange-staticrange
+  constructor(globalObject, args) {
+    const { startContainer, startOffset, endContainer, endOffset } = args[0];
+
+    if (
+      startContainer.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE ||
+      startContainer.nodeType === NODE_TYPE.ATTRIBUTE_NODE ||
+      endContainer.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE ||
+      endContainer.nodeType === NODE_TYPE.ATTRIBUTE_NODE
+    ) {
+      throw DOMException.create(globalObject, ["The supplied node is incorrect.", "InvalidNodeTypeError"]);
+    }
+
+    super(globalObject, [], {
+      start: {
+        node: startContainer,
+        offset: startOffset
+      },
+      end: {
+        node: endContainer,
+        offset: endOffset
+      }
+    });
+  }
+}
+
+module.exports = {
+  implementation: StaticRangeImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/range/boundary-point.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/range/boundary-point.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/range/boundary-point.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,47 @@
+"use strict";
+
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { nodeRoot, isFollowing, isInclusiveAncestor } = require("../helpers/node");
+
+// Returns 0 if equal, +1 for after and -1 for before
+// https://dom.spec.whatwg.org/#concept-range-bp-after
+function compareBoundaryPointsPosition(bpA, bpB) {
+  const { node: nodeA, offset: offsetA } = bpA;
+  const { node: nodeB, offset: offsetB } = bpB;
+
+  if (nodeRoot(nodeA) !== nodeRoot(nodeB)) {
+    throw new Error(`Internal Error: Boundary points should have the same root!`);
+  }
+
+  if (nodeA === nodeB) {
+    if (offsetA === offsetB) {
+      return 0;
+    } else if (offsetA < offsetB) {
+      return -1;
+    }
+
+    return 1;
+  }
+
+  if (isFollowing(nodeA, nodeB)) {
+    return compareBoundaryPointsPosition(bpB, bpA) === -1 ? 1 : -1;
+  }
+
+  if (isInclusiveAncestor(nodeA, nodeB)) {
+    let child = nodeB;
+
+    while (domSymbolTree.parent(child) !== nodeA) {
+      child = domSymbolTree.parent(child);
+    }
+
+    if (domSymbolTree.index(child) < offsetA) {
+      return 1;
+    }
+  }
+
+  return -1;
+}
+
+module.exports = {
+  compareBoundaryPointsPosition
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,342 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const NODE_TYPE = require("../node-type");
+const { nodeLength, nodeRoot } = require("../helpers/node");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { compareBoundaryPointsPosition } = require("../range/boundary-point");
+
+const { setBoundaryPointStart, setBoundaryPointEnd } = require("../range/Range-impl");
+
+const Range = require("../generated/Range");
+const { implForWrapper } = require("../generated/utils");
+
+// https://w3c.github.io/selection-api/#dfn-direction
+const SELECTION_DIRECTION = {
+  FORWARDS: 1,
+  BACKWARDS: -1,
+  DIRECTIONLESS: 0
+};
+
+// https://w3c.github.io/selection-api/#dom-selection
+class SelectionImpl {
+  constructor(globalObject) {
+    this._range = null;
+    this._direction = SELECTION_DIRECTION.DIRECTIONLESS;
+
+    this._globalObject = globalObject;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-anchornode
+  get anchorNode() {
+    const anchor = this._anchor;
+    return anchor ? anchor.node : null;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-anchoroffset
+  get anchorOffset() {
+    const anchor = this._anchor;
+    return anchor ? anchor.offset : 0;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-focusnode
+  get focusNode() {
+    const focus = this._focus;
+    return focus ? focus.node : null;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-focusoffset
+  get focusOffset() {
+    const focus = this._focus;
+    return focus ? focus.offset : 0;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-iscollapsed
+  get isCollapsed() {
+    return this._range === null || this._range.collapsed;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-rangecount
+  get rangeCount() {
+    return this._isEmpty() ? 0 : 1;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-type
+  get type() {
+    if (this._isEmpty()) {
+      return "None";
+    } else if (this._range.collapsed) {
+      return "Caret";
+    }
+
+    return "Range";
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-getrangeat
+  getRangeAt(index) {
+    if (index !== 0 || this._isEmpty()) {
+      throw DOMException.create(this._globalObject, ["Invalid range index.", "IndexSizeError"]);
+    }
+
+    return this._range;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-addrange
+  addRange(range) {
+    if (range._root === implForWrapper(this._globalObject._document) && this.rangeCount === 0) {
+      this._associateRange(range);
+    }
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-removerange
+  removeRange(range) {
+    if (range !== this._range) {
+      throw DOMException.create(this._globalObject, ["Invalid range.", "NotFoundError"]);
+    }
+
+    this._associateRange(null);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-removeallranges
+  removeAllRanges() {
+    this._associateRange(null);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-empty
+  empty() {
+    this.removeAllRanges();
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-collapse
+  collapse(node, offset) {
+    if (node === null) {
+      this.removeAllRanges();
+      return;
+    }
+
+    if (node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
+      throw DOMException.create(this._globalObject, [
+        "DocumentType Node can't be used as boundary point.",
+        "InvalidNodeTypeError"
+      ]);
+    }
+
+    if (offset > nodeLength(node)) {
+      throw DOMException.create(this._globalObject, ["Invalid range index.", "IndexSizeError"]);
+    }
+
+    if (nodeRoot(node) !== implForWrapper(this._globalObject._document)) {
+      return;
+    }
+
+    const newRange = Range.createImpl(this._globalObject, [], {
+      start: { node, offset: 0 },
+      end: { node, offset: 0 }
+    });
+
+    setBoundaryPointStart(newRange, node, offset);
+    setBoundaryPointEnd(newRange, node, offset);
+
+    this._associateRange(newRange);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-setposition
+  setPosition(node, offset) {
+    this.collapse(node, offset);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-collapsetostart
+  collapseToStart() {
+    if (this._isEmpty()) {
+      throw DOMException.create(this._globalObject, ["There is no selection to collapse.", "InvalidStateError"]);
+    }
+
+    const { node, offset } = this._range._start;
+    const newRange = Range.createImpl(this._globalObject, [], {
+      start: { node, offset },
+      end: { node, offset }
+    });
+
+    this._associateRange(newRange);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-collapsetoend
+  collapseToEnd() {
+    if (this._isEmpty()) {
+      throw DOMException.create(this._globalObject, ["There is no selection to collapse.", "InvalidStateError"]);
+    }
+
+    const { node, offset } = this._range._end;
+    const newRange = Range.createImpl(this._globalObject, [], {
+      start: { node, offset },
+      end: { node, offset }
+    });
+
+    this._associateRange(newRange);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-extend
+  extend(node, offset) {
+    if (nodeRoot(node) !== implForWrapper(this._globalObject._document)) {
+      return;
+    }
+
+    if (this._isEmpty()) {
+      throw DOMException.create(this._globalObject, ["There is no selection to extend.", "InvalidStateError"]);
+    }
+
+    const { _anchor: oldAnchor } = this;
+    const newFocus = { node, offset };
+
+    const newRange = Range.createImpl(this._globalObject, [], {
+      start: { node, offset: 0 },
+      end: { node, offset: 0 }
+    });
+
+    if (nodeRoot(node) !== this._range._root) {
+      setBoundaryPointStart(newRange, newFocus.node, newFocus.offset);
+      setBoundaryPointEnd(newRange, newFocus.node, newFocus.offset);
+    } else if (compareBoundaryPointsPosition(oldAnchor, newFocus) <= 0) {
+      setBoundaryPointStart(newRange, oldAnchor.node, oldAnchor.offset);
+      setBoundaryPointEnd(newRange, newFocus.node, newFocus.offset);
+    } else {
+      setBoundaryPointStart(newRange, newFocus.node, newFocus.offset);
+      setBoundaryPointEnd(newRange, oldAnchor.node, oldAnchor.offset);
+    }
+
+    this._associateRange(newRange);
+
+    this._direction = compareBoundaryPointsPosition(newFocus, oldAnchor) === -1 ?
+      SELECTION_DIRECTION.BACKWARDS :
+      SELECTION_DIRECTION.FORWARDS;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-setbaseandextent
+  setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset) {
+    if (anchorOffset > nodeLength(anchorNode) || focusOffset > nodeLength(focusNode)) {
+      throw DOMException.create(this._globalObject, ["Invalid anchor or focus offset.", "IndexSizeError"]);
+    }
+
+    const document = implForWrapper(this._globalObject._document);
+    if (document !== nodeRoot(anchorNode) || document !== nodeRoot(focusNode)) {
+      return;
+    }
+
+    const anchor = { node: anchorNode, offset: anchorOffset };
+    const focus = { node: focusNode, offset: focusOffset };
+
+    let newRange;
+    if (compareBoundaryPointsPosition(anchor, focus) === -1) {
+      newRange = Range.createImpl(this._globalObject, [], {
+        start: { node: anchor.node, offset: anchor.offset },
+        end: { node: focus.node, offset: focus.offset }
+      });
+    } else {
+      newRange = Range.createImpl(this._globalObject, [], {
+        start: { node: focus.node, offset: focus.offset },
+        end: { node: anchor.node, offset: anchor.offset }
+      });
+    }
+
+    this._associateRange(newRange);
+
+    this._direction = compareBoundaryPointsPosition(focus, anchor) === -1 ?
+      SELECTION_DIRECTION.BACKWARDS :
+      SELECTION_DIRECTION.FORWARDS;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-selectallchildren
+  selectAllChildren(node) {
+    if (node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) {
+      throw DOMException.create(this._globalObject, [
+        "DocumentType Node can't be used as boundary point.",
+        "InvalidNodeTypeError"
+      ]);
+    }
+
+    const document = implForWrapper(this._globalObject._document);
+    if (document !== nodeRoot(node)) {
+      return;
+    }
+
+    const length = domSymbolTree.childrenCount(node);
+
+    const newRange = Range.createImpl(this._globalObject, [], {
+      start: { node, offset: 0 },
+      end: { node, offset: 0 }
+    });
+
+    setBoundaryPointStart(newRange, node, 0);
+    setBoundaryPointEnd(newRange, node, length);
+
+    this._associateRange(newRange);
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-deletefromdocument
+  deleteFromDocument() {
+    if (!this._isEmpty()) {
+      this._range.deleteContents();
+    }
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-containsnode
+  containsNode(node, allowPartialContainment) {
+    if (this._isEmpty() || nodeRoot(node) !== implForWrapper(this._globalObject._document)) {
+      return false;
+    }
+
+    const { _start, _end } = this._range;
+
+    const startIsBeforeNode = compareBoundaryPointsPosition(_start, { node, offset: 0 }) === -1;
+    const endIsAfterNode = compareBoundaryPointsPosition(_end, { node, offset: nodeLength(node) }) === 1;
+
+    return allowPartialContainment ?
+      startIsBeforeNode || endIsAfterNode :
+      startIsBeforeNode && endIsAfterNode;
+  }
+
+  // https://w3c.github.io/selection-api/#dom-selection-stringifier
+  toString() {
+    return this._range ? this._range.toString() : "";
+  }
+
+  // https://w3c.github.io/selection-api/#dfn-empty
+  _isEmpty() {
+    return this._range === null;
+  }
+
+  // https://w3c.github.io/selection-api/#dfn-anchor
+  get _anchor() {
+    if (!this._range) {
+      return null;
+    }
+
+    return this._direction === SELECTION_DIRECTION.FORWARDS ?
+      this._range._start :
+      this._range._end;
+  }
+
+  // https://w3c.github.io/selection-api/#dfn-focus
+  get _focus() {
+    if (!this._range) {
+      return null;
+    }
+
+    return this._direction === SELECTION_DIRECTION.FORWARDS ?
+      this._range._end :
+      this._range._start;
+  }
+
+  _associateRange(newRange) {
+    this._range = newRange;
+    this._direction = newRange === null ? SELECTION_DIRECTION.DIRECTIONLESS : SELECTION_DIRECTION.FORWARDS;
+
+    // TODO: Emit "selectionchange" event. At this time, there is currently no test in WPT covering this.
+    // https://w3c.github.io/selection-api/#selectionchange-event
+  }
+}
+
+module.exports = {
+  implementation: SelectionImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGAnimatedString-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGAnimatedString-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGAnimatedString-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,38 @@
+"use strict";
+
+class SVGAnimatedStringImpl {
+  constructor(globalObject, args, privateData) {
+    this._element = privateData.element;
+    this._attribute = privateData.attribute;
+    this._attributeDeprecated = privateData.attributeDeprecated; // can be undefined
+    this._initialValue = privateData.initialValue; // can be undefined
+  }
+
+  get baseVal() {
+    if (!this._element.hasAttributeNS(null, this._attribute)) {
+      if (this._attributeDeprecated !== undefined && this._element.hasAttributeNS(null, this._attributeDeprecated)) {
+        return this._element.getAttributeNS(null, this._attributeDeprecated);
+      } else if (this._initialValue !== undefined) {
+        return this._initialValue;
+      }
+      return "";
+    }
+    return this._element.getAttributeNS(null, this._attribute);
+  }
+
+  set baseVal(base) {
+    if (!this._element.hasAttributeNS(null, this._attribute) &&
+        this._attributeDeprecated !== undefined &&
+        this._element.hasAttributeNS(null, this._attributeDeprecated)) {
+      this._element.setAttributeNS(null, this._attributeDeprecated, base);
+    } else {
+      this._element.setAttributeNS(null, this._attribute, base);
+    }
+  }
+
+  get animVal() {
+    return this.baseVal;
+  }
+}
+
+exports.implementation = SVGAnimatedStringImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGListBase.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGListBase.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGListBase.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,195 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const idlUtils = require("../generated/utils");
+const { attach, detach } = require("../helpers/svg/basic-types");
+
+// https://svgwg.org/svg2-draft/types.html#ListInterfaces
+
+// Child classes must implement _reserialize()
+class List {
+  _initList({
+    element,
+    attribute,
+    readOnly = false
+  }) {
+    this._element = element;
+    this._attribute = attribute;
+    this._attributeRegistryEntry = element.constructor.attributeRegistry.get(attribute);
+    this._readOnly = readOnly;
+    this._list = [];
+    this._version = -1;
+  }
+
+  get _needsResync() {
+    return this._version < this._element._version;
+  }
+
+  _synchronize() {
+    if (!this._needsResync) {
+      return;
+    }
+    let value = [];
+    if (this._element.hasAttributeNS(null, this._attribute)) {
+      value = this._attributeRegistryEntry.getValue(this._element.getAttributeNS(null, this._attribute));
+    }
+    if (value.length === 0 && this._attributeRegistryEntry.initialValue !== undefined) {
+      value = this._attributeRegistryEntry.getValue(this._attributeRegistryEntry.initialValue);
+    }
+    // TODO: support non-DOMString lists.
+    this._list = value;
+    this._version = this._element._version;
+  }
+
+  _reserialize() {
+    const elements = this._list;
+    this._element.setAttributeNS(null, this._attribute, this._attributeRegistryEntry.serialize(elements));
+    // Prevent ping-ponging back and forth between _reserialize() and _synchronize().
+    this._version = this._element._version;
+  }
+
+  [idlUtils.supportsPropertyIndex](index) {
+    this._synchronize();
+    return index >= 0 && index < this.length;
+  }
+
+  get [idlUtils.supportedPropertyIndices]() {
+    this._synchronize();
+    return this._list.keys();
+  }
+
+  get length() {
+    this._synchronize();
+    return this._list.length;
+  }
+
+  get numberOfItems() {
+    this._synchronize();
+    return this._list.length;
+  }
+
+  clear() {
+    this._synchronize();
+    if (this._readOnly) {
+      throw DOMException.create(this._globalObject, [
+        "Attempting to modify a read-only list",
+        "NoModificationAllowedError"
+      ]);
+    }
+    for (const item of this._list) {
+      detach(item);
+    }
+    this._list.length = 0;
+    this._reserialize();
+  }
+
+  initialize(newItem) {
+    this._synchronize();
+    if (this._readOnly) {
+      throw DOMException.create(this._globalObject, [
+        "Attempting to modify a read-only list",
+        "NoModificationAllowedError"
+      ]);
+    }
+    for (const item of this._list) {
+      detach(item);
+    }
+    this._list.length = 0;
+    // TODO: clone non-DOMString list elements.
+    attach(newItem, this);
+    this._list.push(newItem);
+    this._reserialize();
+  }
+
+  getItem(index) {
+    this._synchronize();
+    if (index >= this._list.length) {
+      throw DOMException.create(this._globalObject, [
+        `The index provided (${index}) is greater than or equal to the maximum bound (${this._list.length}).`,
+        "IndexSizeError"
+      ]);
+    }
+    return this._list[index];
+  }
+
+  insertItemBefore(newItem, index) {
+    this._synchronize();
+    if (this._readOnly) {
+      throw DOMException.create(this._globalObject, [
+        "Attempting to modify a read-only list",
+        "NoModificationAllowedError"
+      ]);
+    }
+    // TODO: clone non-DOMString list elements.
+    if (index > this._list.length) {
+      index = this._list.length;
+    }
+    this._list.splice(index, 0, newItem);
+    attach(newItem, this);
+    this._reserialize();
+    return newItem;
+  }
+
+  replaceItem(newItem, index) {
+    this._synchronize();
+    if (this._readOnly) {
+      throw DOMException.create(this._globalObject, [
+        "Attempting to modify a read-only list",
+        "NoModificationAllowedError"
+      ]);
+    }
+    if (index >= this._list.length) {
+      throw DOMException.create(this._globalObject, [
+        `The index provided (${index}) is greater than or equal to the maximum bound (${this._list.length}).`,
+        "IndexSizeError"
+      ]);
+    }
+    // TODO: clone non-DOMString list elements.
+    detach(this._list[index]);
+    this._list[index] = newItem;
+    attach(newItem, this);
+    this._reserialize();
+    return newItem;
+  }
+
+  removeItem(index) {
+    this._synchronize();
+    if (this._readOnly) {
+      throw DOMException.create(this._globalObject, [
+        "Attempting to modify a read-only list",
+        "NoModificationAllowedError"
+      ]);
+    }
+    if (index >= this._list.length) {
+      throw DOMException.create(this._globalObject, [
+        `The index provided (${index}) is greater than or equal to the maximum bound (${this._list.length}).`,
+        "IndexSizeError"
+      ]);
+    }
+    const item = this._list[index];
+    detach(item);
+    this._list.splice(index, 1);
+    this._reserialize();
+    return item;
+  }
+
+  appendItem(newItem) {
+    this._synchronize();
+    // TODO: clone non-DOMString list elements.
+    this._list.push(newItem);
+    attach(newItem, this);
+    this._reserialize();
+    return newItem;
+  }
+
+  [idlUtils.indexedSetNew](index, value) {
+    // Note: this will always throw a IndexSizeError.
+    this.replaceItem(value, index);
+  }
+
+  [idlUtils.indexedSetExisting](index, value) {
+    this.replaceItem(value, index);
+  }
+}
+
+module.exports = List;
Index: frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGNumber-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGNumber-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGNumber-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,48 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+
+class SVGNumberImpl {
+  constructor(globalObject, args, privateData) {
+    // Delegate to parent List object for (almost) everything related to reflection.
+    this._parentList = privateData.parentList;
+    this._value = 0;
+  }
+
+  get _readOnly() {
+    if (this._parentList !== undefined) {
+      return this._parentList._readOnly;
+    }
+    return false;
+  }
+
+  _synchronize() {
+    if (this._parentList !== undefined) {
+      this._parentList._synchronize();
+    }
+  }
+
+  _reserialize() {
+    if (this._parentList !== undefined) {
+      this._parentList._reserialize();
+    }
+  }
+
+  get value() {
+    this._synchronize();
+    return this._value;
+  }
+
+  set value(value) {
+    if (this._readOnly) {
+      throw DOMException.create(this._globalObject, [
+        "Attempting to modify a read-only SVGNumber",
+        "NoModificationAllowedError"
+      ]);
+    }
+    this._value = value;
+    this._reserialize();
+  }
+}
+
+exports.implementation = SVGNumberImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGStringList-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGStringList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/svg/SVGStringList-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,16 @@
+"use strict";
+
+const { mixin } = require("../../utils");
+const SVGListBase = require("./SVGListBase");
+
+class SVGStringListImpl {
+  constructor(globalObject, args, privateData) {
+    this._globalObject = globalObject;
+
+    this._initList(privateData);
+  }
+}
+
+mixin(SVGStringListImpl.prototype, SVGListBase.prototype);
+
+exports.implementation = SVGStringListImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/traversal/NodeIterator-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/traversal/NodeIterator-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/traversal/NodeIterator-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,127 @@
+"use strict";
+const { hasWeakRefs } = require("../../utils");
+const { domSymbolTree } = require("../helpers/internal-constants");
+const { filter, FILTER_ACCEPT } = require("./helpers");
+
+exports.implementation = class NodeIteratorImpl {
+  constructor(globalObject, args, privateData) {
+    this._active = false;
+    this.root = privateData.root;
+    this.whatToShow = privateData.whatToShow;
+    this.filter = privateData.filter;
+
+    this._referenceNode = this.root;
+    this._pointerBeforeReferenceNode = true;
+
+    // This is used to deactivate the NodeIterator if there are too many working in a Document at the same time.
+    // Without weak references, a JS implementation of NodeIterator will leak, since we can't know when to clean it up.
+    // This ensures we force a clean up of those beyond some maximum (specified by the Document).
+    if (!hasWeakRefs) {
+      this._working = true;
+    }
+
+    this._globalObject = globalObject;
+  }
+
+  get referenceNode() {
+    this._throwIfNotWorking();
+    return this._referenceNode;
+  }
+
+  get pointerBeforeReferenceNode() {
+    this._throwIfNotWorking();
+    return this._pointerBeforeReferenceNode;
+  }
+
+  nextNode() {
+    this._throwIfNotWorking();
+    return this._traverse("next");
+  }
+
+  previousNode() {
+    this._throwIfNotWorking();
+    return this._traverse("previous");
+  }
+
+  detach() {
+    // Intentionally do nothing, per spec.
+  }
+
+  // Called by Documents.
+  _preRemovingSteps(toBeRemovedNode) {
+    // Second clause is https://github.com/whatwg/dom/issues/496
+    if (!toBeRemovedNode.contains(this._referenceNode) || toBeRemovedNode === this.root) {
+      return;
+    }
+
+    if (this._pointerBeforeReferenceNode) {
+      let next = null;
+      let candidateForNext = domSymbolTree.following(toBeRemovedNode, { skipChildren: true });
+      while (candidateForNext !== null) {
+        if (this.root.contains(candidateForNext)) {
+          next = candidateForNext;
+          break;
+        }
+        candidateForNext = domSymbolTree.following(candidateForNext, { skipChildren: true });
+      }
+
+      if (next !== null) {
+        this._referenceNode = next;
+        return;
+      }
+
+      this._pointerBeforeReferenceNode = false;
+    }
+
+    const { previousSibling } = toBeRemovedNode;
+    this._referenceNode = previousSibling === null ?
+                          toBeRemovedNode.parentNode :
+                          domSymbolTree.lastInclusiveDescendant(toBeRemovedNode.previousSibling);
+  }
+
+  // Only called by getters and methods that are affected by the pre-removing steps
+  _throwIfNotWorking() {
+    if (!hasWeakRefs && !this._working) {
+      throw Error(`This NodeIterator is no longer working. More than 10 iterators are being used concurrently. ` +
+        `Using more than 10 node iterators requires WeakRef support.`);
+    }
+  }
+
+  _traverse(direction) {
+    let node = this._referenceNode;
+    let beforeNode = this._pointerBeforeReferenceNode;
+
+    while (true) {
+      if (direction === "next") {
+        if (!beforeNode) {
+          node = domSymbolTree.following(node, { root: this.root });
+
+          if (!node) {
+            return null;
+          }
+        }
+
+        beforeNode = false;
+      } else if (direction === "previous") {
+        if (beforeNode) {
+          node = domSymbolTree.preceding(node, { root: this.root });
+
+          if (!node) {
+            return null;
+          }
+        }
+
+        beforeNode = true;
+      }
+
+      const result = filter(this, node);
+      if (result === FILTER_ACCEPT) {
+        break;
+      }
+    }
+
+    this._referenceNode = node;
+    this._pointerBeforeReferenceNode = beforeNode;
+    return node;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/traversal/TreeWalker-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/traversal/TreeWalker-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/traversal/TreeWalker-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,217 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { filter, FILTER_ACCEPT, FILTER_REJECT, FILTER_SKIP } = require("./helpers");
+
+const FIRST = false;
+const LAST = true;
+const NEXT = false;
+const PREVIOUS = true;
+
+exports.implementation = class TreeWalkerImpl {
+  constructor(globalObject, args, privateData) {
+    this._active = false;
+    this.root = privateData.root;
+    this.currentNode = this.root;
+    this.whatToShow = privateData.whatToShow;
+    this.filter = privateData.filter;
+
+    this._globalObject = globalObject;
+  }
+
+  get currentNode() {
+    return this._currentNode;
+  }
+
+  set currentNode(node) {
+    if (node === null) {
+      throw DOMException.create(this._globalObject, ["Cannot set currentNode to null", "NotSupportedError"]);
+    }
+
+    this._currentNode = node;
+  }
+
+  parentNode() {
+    let node = this._currentNode;
+    while (node !== null && node !== this.root) {
+      node = node.parentNode;
+
+      if (node !== null && filter(this, node) === FILTER_ACCEPT) {
+        return (this._currentNode = node);
+      }
+    }
+    return null;
+  }
+
+  firstChild() {
+    return this._traverseChildren(FIRST);
+  }
+
+  lastChild() {
+    return this._traverseChildren(LAST);
+  }
+
+  previousSibling() {
+    return this._traverseSiblings(PREVIOUS);
+  }
+
+  nextSibling() {
+    return this._traverseSiblings(NEXT);
+  }
+
+  previousNode() {
+    let node = this._currentNode;
+
+    while (node !== this.root) {
+      let sibling = node.previousSibling;
+
+      while (sibling !== null) {
+        node = sibling;
+        let result = filter(this, node);
+
+        while (result !== FILTER_REJECT && node.hasChildNodes()) {
+          node = node.lastChild;
+          result = filter(this, node);
+        }
+
+        if (result === FILTER_ACCEPT) {
+          return (this._currentNode = node);
+        }
+
+        sibling = node.previousSibling;
+      }
+
+      if (node === this.root || node.parentNode === null) {
+        return null;
+      }
+
+      node = node.parentNode;
+
+      if (filter(this, node) === FILTER_ACCEPT) {
+        return (this._currentNode = node);
+      }
+    }
+
+    return null;
+  }
+
+  nextNode() {
+    let node = this._currentNode;
+    let result = FILTER_ACCEPT;
+
+    for (;;) {
+      while (result !== FILTER_REJECT && node.hasChildNodes()) {
+        node = node.firstChild;
+        result = filter(this, node);
+        if (result === FILTER_ACCEPT) {
+          return (this._currentNode = node);
+        }
+      }
+
+      do {
+        if (node === this.root) {
+          return null;
+        }
+
+        const sibling = node.nextSibling;
+
+        if (sibling !== null) {
+          node = sibling;
+          break;
+        }
+
+        node = node.parentNode;
+      } while (node !== null);
+
+      if (node === null) {
+        return null;
+      }
+
+      result = filter(this, node);
+
+      if (result === FILTER_ACCEPT) {
+        return (this._currentNode = node);
+      }
+    }
+  }
+
+  _traverseChildren(type) {
+    let node = this._currentNode;
+    node = type === FIRST ? node.firstChild : node.lastChild;
+
+    if (node === null) {
+      return null;
+    }
+
+    main: for (;;) {
+      const result = filter(this, node);
+
+      if (result === FILTER_ACCEPT) {
+        return (this._currentNode = node);
+      }
+
+      if (result === FILTER_SKIP) {
+        const child = type === FIRST ? node.firstChild : node.lastChild;
+
+        if (child !== null) {
+          node = child;
+          continue;
+        }
+      }
+
+      for (;;) {
+        const sibling = type === FIRST ? node.nextSibling : node.previousSibling;
+
+        if (sibling !== null) {
+          node = sibling;
+          continue main;
+        }
+
+        const parent = node.parentNode;
+
+        if (parent === null || parent === this.root || parent === this._currentNode) {
+          return null;
+        }
+
+        node = parent;
+      }
+    }
+  }
+
+  _traverseSiblings(type) {
+    let node = this._currentNode;
+
+    if (node === this.root) {
+      return null;
+    }
+
+    for (;;) {
+      let sibling = type === NEXT ? node.nextSibling : node.previousSibling;
+
+      while (sibling !== null) {
+        node = sibling;
+        const result = filter(this, node);
+
+        if (result === FILTER_ACCEPT) {
+          return (this._currentNode = node);
+        }
+
+        sibling = type === NEXT ? node.firstChild : node.lastChild;
+
+        if (result === FILTER_REJECT || sibling === null) {
+          sibling = type === NEXT ? node.nextSibling : node.previousSibling;
+        }
+      }
+
+      node = node.parentNode;
+
+      if (node === null || node === this.root) {
+        return null;
+      }
+
+      if (filter(this, node) === FILTER_ACCEPT) {
+        return null;
+      }
+    }
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/traversal/helpers.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/traversal/helpers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/traversal/helpers.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,44 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const conversions = require("webidl-conversions");
+
+exports.FILTER_ACCEPT = 1; // NodeFilter.FILTER_ACCEPT
+exports.FILTER_REJECT = 2; // NodeFilter.FILTER_REJECT
+exports.FILTER_SKIP = 3; // NodeFilter.FILTER_SKIP
+
+exports.filter = (nodeIteratorOrTreeWalkerImpl, nodeImpl) => {
+  if (nodeIteratorOrTreeWalkerImpl._active) {
+    throw DOMException.create(nodeIteratorOrTreeWalkerImpl._globalObject, [
+      "Recursive node filtering",
+      "InvalidStateError"
+    ]);
+  }
+
+  const n = nodeImpl.nodeType - 1;
+
+  if (!((1 << n) & nodeIteratorOrTreeWalkerImpl.whatToShow)) {
+    return exports.FILTER_SKIP;
+  }
+
+  // Saving in a variable is important so we don't accidentally call it as a method later.
+  const { filter } = nodeIteratorOrTreeWalkerImpl;
+
+  if (filter === null) {
+    return exports.FILTER_ACCEPT;
+  }
+
+  nodeIteratorOrTreeWalkerImpl._active = true;
+
+  let result;
+
+  // https://github.com/whatwg/dom/issues/494
+  try {
+    result = filter(nodeImpl);
+  } finally {
+    nodeIteratorOrTreeWalkerImpl._active = false;
+  }
+
+  result = conversions["unsigned short"](result);
+
+  return result;
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/websockets/WebSocket-impl-browser.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/websockets/WebSocket-impl-browser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/websockets/WebSocket-impl-browser.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,175 @@
+/* eslint-env browser */
+
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { parseURL, serializeURL, serializeURLOrigin } = require("whatwg-url");
+
+const { setupForSimpleEventAccessors } = require("../helpers/create-event-accessor");
+const { fireAnEvent } = require("../helpers/events");
+
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+
+const idlUtils = require("../generated/utils");
+const Blob = require("../generated/Blob");
+const CloseEvent = require("../generated/CloseEvent");
+const MessageEvent = require("../generated/MessageEvent");
+
+const productions = {
+  // https://tools.ietf.org/html/rfc7230#section-3.2.6
+  token: /^[!#$%&'*+\-.^_`|~\dA-Za-z]+$/
+};
+
+// https://tools.ietf.org/html/rfc6455#section-4.3
+// See Sec-WebSocket-Protocol-Client, which is for the syntax of an entire header value. This function checks if a
+// single header conforms to the rules.
+function verifySecWebSocketProtocol(str) {
+  return productions.token.test(str);
+}
+
+const openSockets = new WeakMap();
+
+class WebSocketImpl extends EventTargetImpl {
+  constructor(constructorArgs, privateData) {
+    super([], privateData);
+    const { window } = privateData;
+    this._ownerDocument = idlUtils.implForWrapper(window._document);
+
+    const url = constructorArgs[0];
+    let protocols = constructorArgs[1] !== undefined ? constructorArgs[1] : [];
+
+    const urlRecord = parseURL(url);
+    if (urlRecord === null) {
+      throw DOMException.create(this._globalObject, [`The URL '${url}' is invalid.`, "SyntaxError"]);
+    }
+    if (urlRecord.scheme !== "ws" && urlRecord.scheme !== "wss") {
+      throw DOMException.create(this._globalObject, [
+        `The URL's scheme must be either 'ws' or 'wss'. '${urlRecord.scheme}' is not allowed.`,
+        "SyntaxError"
+      ]);
+    }
+    if (urlRecord.fragment !== null) {
+      throw DOMException.create(this._globalObject, [
+        `The URL contains a fragment identifier ('${urlRecord.fragment}'). Fragment identifiers ` +
+        "are not allowed in WebSocket URLs.",
+        "SyntaxError"
+      ]);
+    }
+
+    if (typeof protocols === "string") {
+      protocols = [protocols];
+    }
+    const protocolSet = new Set();
+    for (const protocol of protocols) {
+      if (!verifySecWebSocketProtocol(protocol)) {
+        throw DOMException.create(this._globalObject, [`The subprotocol '${protocol}' is invalid.`, "SyntaxError"]);
+      }
+      const lowered = protocol.toLowerCase();
+      if (protocolSet.has(lowered)) {
+        throw DOMException.create(this._globalObject, [
+          `The subprotocol '${protocol}' is duplicated.`,
+          "SyntaxError"
+        ]);
+      }
+      protocolSet.add(lowered);
+    }
+
+    this._urlRecord = urlRecord;
+    this.url = serializeURL(urlRecord);
+
+    this._ws = new WebSocket(this.url, protocols);
+
+    this._ws.onopen = () => {
+      fireAnEvent("open", this);
+    };
+    this._ws.onerror = () => {
+      fireAnEvent("error", this);
+    };
+    this._ws.onclose = event => {
+      fireAnEvent("close", this, CloseEvent, {
+        wasClean: event.wasClean,
+        code: event.code,
+        reason: event.reason
+      });
+    };
+    this._ws.onmessage = event => {
+      fireAnEvent("message", this, MessageEvent, {
+        data: event.data,
+        origin: serializeURLOrigin(this._urlRecord)
+      });
+    };
+
+    let openSocketsForWindow = openSockets.get(window._globalProxy);
+    if (openSocketsForWindow === undefined) {
+      openSocketsForWindow = new Set();
+      openSockets.set(window._globalProxy, openSocketsForWindow);
+    }
+    openSocketsForWindow.add(this);
+  }
+
+  // https://html.spec.whatwg.org/multipage/web-sockets.html#make-disappear
+  _makeDisappear() {
+    this._eventListeners = Object.create(null);
+    this._ws.close(1001);
+  }
+
+  static cleanUpWindow(window) {
+    const openSocketsForWindow = openSockets.get(window._globalProxy);
+    if (openSocketsForWindow !== undefined) {
+      for (const ws of openSocketsForWindow) {
+        ws._makeDisappear();
+      }
+    }
+  }
+
+  get readyState() {
+    return this._ws.readyState;
+  }
+
+  get bufferedAmount() {
+    return this._ws.bufferedAmount;
+  }
+
+  get extensions() {
+    return this._ws.extensions;
+  }
+
+  get protocol() {
+    return this._ws.protocol;
+  }
+
+  close(code = undefined, reason = undefined) {
+    if (code !== undefined && code !== 1000 && !(code >= 3000 && code <= 4999)) {
+      throw DOMException.create(this._globalObject, [
+        `The code must be either 1000, or between 3000 and 4999. ${code} is neither.`,
+        "InvalidAccessError"
+      ]);
+    }
+    if (reason !== undefined && Buffer.byteLength(reason, "utf8") > 123) {
+      throw DOMException.create(this._globalObject, [
+        "The message must not be greater than 123 bytes.",
+        "SyntaxError"
+      ]);
+    }
+    return this._ws.close(code, reason);
+  }
+
+  get binaryType() {
+    return this._ws.binaryType;
+  }
+
+  set binaryType(val) {
+    this._ws.binaryType = val;
+  }
+
+  send(data) {
+    if (Blob.isImpl(data)) {
+      data = data._buffer;
+    }
+    this._ws.send(data);
+  }
+}
+
+setupForSimpleEventAccessors(WebSocketImpl.prototype, ["open", "message", "error", "close"]);
+
+exports.implementation = WebSocketImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/websockets/WebSocket-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/websockets/WebSocket-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/websockets/WebSocket-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,328 @@
+"use strict";
+
+const nodeURL = require("url");
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const { parseURL, serializeURL, serializeURLOrigin } = require("whatwg-url");
+const WebSocket = require("ws");
+
+const { setupForSimpleEventAccessors } = require("../helpers/create-event-accessor");
+const { fireAnEvent } = require("../helpers/events");
+const { isArrayBuffer } = require("../generated/utils");
+const { copyToArrayBufferInNewRealm } = require("../helpers/binary-data");
+
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+
+const idlUtils = require("../generated/utils");
+const Blob = require("../generated/Blob");
+const CloseEvent = require("../generated/CloseEvent");
+const MessageEvent = require("../generated/MessageEvent");
+
+const CONNECTING = 0;
+const OPEN = 1;
+const CLOSING = 2;
+const CLOSED = 3;
+
+const productions = {
+  // https://tools.ietf.org/html/rfc7230#section-3.2.6
+  token: /^[!#$%&'*+\-.^_`|~\dA-Za-z]+$/
+};
+
+const readyStateWSToDOM = [];
+readyStateWSToDOM[WebSocket.CONNECTING] = CONNECTING;
+readyStateWSToDOM[WebSocket.OPEN] = OPEN;
+readyStateWSToDOM[WebSocket.CLOSING] = CLOSING;
+readyStateWSToDOM[WebSocket.CLOSED] = CLOSED;
+
+// https://tools.ietf.org/html/rfc6455#section-4.3
+// See Sec-WebSocket-Protocol-Client, which is for the syntax of an entire header value. This function checks if a
+// single header conforms to the rules.
+function verifySecWebSocketProtocol(str) {
+  return productions.token.test(str);
+}
+
+class PromiseQueues extends WeakMap {
+  get(window) {
+    const cur = super.get(window);
+    return cur !== undefined ? cur : Promise.resolve();
+  }
+}
+
+const openSockets = new WeakMap();
+const openingQueues = new PromiseQueues();
+
+class WebSocketImpl extends EventTargetImpl {
+  constructor(globalObject, args, privateData) {
+    super(globalObject, args, privateData);
+
+    this._ownerDocument = idlUtils.implForWrapper(globalObject._document);
+
+    const url = args[0];
+    let protocols = args[1] !== undefined ? args[1] : [];
+
+    const urlRecord = parseURL(url);
+    if (urlRecord === null) {
+      throw DOMException.create(this._globalObject, [`The URL '${url}' is invalid.`, "SyntaxError"]);
+    }
+    if (urlRecord.scheme !== "ws" && urlRecord.scheme !== "wss") {
+      throw DOMException.create(this._globalObject, [
+        `The URL's scheme must be either 'ws' or 'wss'. '${urlRecord.scheme}' is not allowed.`,
+        "SyntaxError"
+      ]);
+    }
+    if (urlRecord.fragment !== null) {
+      throw DOMException.create(this._globalObject, [
+        `The URL contains a fragment identifier ('${urlRecord.fragment}'). Fragment identifiers ` +
+        "are not allowed in WebSocket URLs.",
+        "SyntaxError"
+      ]);
+    }
+
+    if (typeof protocols === "string") {
+      protocols = [protocols];
+    }
+    const protocolSet = new Set();
+    for (const protocol of protocols) {
+      if (!verifySecWebSocketProtocol(protocol)) {
+        throw DOMException.create(this._globalObject, [`The subprotocol '${protocol}' is invalid.`, "SyntaxError"]);
+      }
+      const lowered = protocol.toLowerCase();
+      if (protocolSet.has(lowered)) {
+        throw DOMException.create(this._globalObject, [
+          `The subprotocol '${protocol}' is duplicated.`,
+          "SyntaxError"
+        ]);
+      }
+      protocolSet.add(lowered);
+    }
+
+    this._urlRecord = urlRecord;
+    this.url = serializeURL(urlRecord);
+    const nodeParsedURL = nodeURL.parse(this.url);
+    this.extensions = "";
+
+    this.binaryType = "blob";
+
+    this._ws = null;
+    // Used when this._ws has not been initialized yet.
+    this._readyState = CONNECTING;
+    this._requiredToFail = false;
+    this.bufferedAmount = 0;
+    this._sendQueue = [];
+
+    let openSocketsForWindow = openSockets.get(globalObject._globalProxy);
+    if (openSocketsForWindow === undefined) {
+      openSocketsForWindow = new Set();
+      openSockets.set(globalObject._globalProxy, openSocketsForWindow);
+    }
+    openSocketsForWindow.add(this);
+
+    openingQueues.set(this._ownerDocument, openingQueues.get(this._ownerDocument).then(() => new Promise(resolve => {
+      // close() called before _ws has been initialized.
+      if (this._requiredToFail) {
+        resolve();
+        this._readyState = CLOSED;
+        this._onConnectionClosed(1006, "");
+        return;
+      }
+
+      this._ws = new WebSocket(this.url, protocols, {
+        headers: {
+          "user-agent": globalObject.navigator.userAgent,
+          "cookie": this._ownerDocument._cookieJar.getCookieStringSync(nodeParsedURL, { http: true }),
+          "origin": globalObject._origin
+        },
+        rejectUnauthorized: this._ownerDocument._strictSSL
+      });
+      this._ws.once("open", () => {
+        resolve();
+        this._onConnectionEstablished();
+      });
+      this._ws.on("message", this._onMessageReceived.bind(this));
+      this._ws.once("close", (...closeArgs) => {
+        resolve();
+        this._onConnectionClosed(...closeArgs);
+      });
+      this._ws.once("upgrade", ({ headers }) => {
+        if (Array.isArray(headers["set-cookie"])) {
+          for (const cookie of headers["set-cookie"]) {
+            this._ownerDocument._cookieJar.setCookieSync(
+              cookie,
+              nodeParsedURL,
+              { http: true, ignoreError: true }
+            );
+          }
+        } else if (headers["set-cookie"] !== undefined) {
+          this._ownerDocument._cookieJar.setCookieSync(
+            headers["set-cookie"],
+            nodeParsedURL,
+            { http: true, ignoreError: true }
+          );
+        }
+      });
+      this._ws.once("error", () => {
+        // The exact error is passed into this callback, but it is ignored as we don't really care about it.
+        resolve();
+        this._requiredToFail = true;
+        // Do not emit an error here, as that will be handled in _onConnectionClosed. ws always emits a close event
+        // after errors.
+      });
+    })));
+  }
+
+  // https://html.spec.whatwg.org/multipage/web-sockets.html#make-disappear
+  _makeDisappear() {
+    this._eventListeners = Object.create(null);
+    this._close(1001);
+  }
+
+  static cleanUpWindow(window) {
+    const openSocketsForWindow = openSockets.get(window._globalProxy);
+    if (openSocketsForWindow !== undefined) {
+      for (const ws of openSocketsForWindow) {
+        ws._makeDisappear();
+      }
+    }
+  }
+
+  // https://html.spec.whatwg.org/multipage/web-sockets.html#feedback-from-the-protocol
+  _onConnectionEstablished() {
+    // readyState is a getter.
+    if (this._ws.extensions !== null) {
+      // Right now, ws only supports one extension, permessage-deflate, without any parameters. This algorithm may need
+      // to be more sophiscated as more extenions are supported.
+      this.extensions = Object.keys(this._ws.extensions).join(", ");
+    }
+    // protocol is a getter.
+    fireAnEvent("open", this);
+  }
+
+  _onMessageReceived(data) {
+    if (this.readyState !== OPEN) {
+      return;
+    }
+    let dataForEvent;
+    if (typeof data === "string") {
+      dataForEvent = data;
+    } else if (this.binaryType === "arraybuffer") {
+      if (isArrayBuffer(data)) {
+        dataForEvent = data;
+      } else if (Array.isArray(data)) {
+        dataForEvent = copyToArrayBufferInNewRealm(Buffer.concat(data), this._globalObject);
+      } else {
+        dataForEvent = copyToArrayBufferInNewRealm(data, this._globalObject);
+      }
+    } else { // this.binaryType === "blob"
+      if (!Array.isArray(data)) {
+        data = [data];
+      }
+      dataForEvent = Blob.create(this._globalObject, [data, { type: "" }]);
+    }
+    fireAnEvent("message", this, MessageEvent, {
+      data: dataForEvent,
+      origin: serializeURLOrigin(this._urlRecord)
+    });
+  }
+
+  _onConnectionClosed(code, reason) {
+    const openSocketsForWindow = openSockets.get(this._ownerDocument._defaultView);
+    openSocketsForWindow.delete(this);
+
+    const wasClean = !this._requiredToFail;
+    if (this._requiredToFail) {
+      fireAnEvent("error", this);
+    }
+    fireAnEvent("close", this, CloseEvent, {
+      wasClean,
+      code,
+      reason
+    });
+  }
+
+  get readyState() {
+    if (this._ws !== null) {
+      return readyStateWSToDOM[this._ws.readyState];
+    }
+    return this._readyState;
+  }
+
+  get protocol() {
+    if (this._ws === null) {
+      return "";
+    }
+    return this._ws.protocol;
+  }
+
+  close(code = undefined, reason = undefined) {
+    if (code !== undefined && code !== 1000 && !(code >= 3000 && code <= 4999)) {
+      throw DOMException.create(this._globalObject, [
+        `The code must be either 1000, or between 3000 and 4999. ${code} is neither.`,
+        "InvalidAccessError"
+      ]);
+    }
+    if (reason !== undefined && Buffer.byteLength(reason, "utf8") > 123) {
+      throw DOMException.create(this._globalObject, [
+        "The message must not be greater than 123 bytes.",
+        "SyntaxError"
+      ]);
+    }
+    this._close(code, reason);
+  }
+
+  _close(code = undefined, reason = undefined) {
+    if (this.readyState === CONNECTING) {
+      this._requiredToFail = true;
+      if (this._ws !== null) {
+        this._ws.terminate();
+      } else {
+        this._readyState = CLOSING;
+      }
+    } else if (this.readyState === OPEN) {
+      this._ws.close(code, reason);
+    }
+  }
+
+  send(data) {
+    if (this.readyState === CONNECTING) {
+      throw DOMException.create(this._globalObject, ["Still in CONNECTING state.", "InvalidStateError"]);
+    }
+    if (this.readyState !== OPEN) {
+      return;
+    }
+    if (Blob.isImpl(data)) {
+      data = data._buffer;
+    }
+    let length;
+    if (typeof data === "string") {
+      length = Buffer.byteLength(data, "utf8");
+    } else {
+      length = data.byteLength;
+    }
+    this.bufferedAmount += length;
+    this._sendQueue.push([data, length]);
+    this._scheduleSend();
+  }
+
+  _actuallySend() {
+    for (const [data, length] of this._sendQueue.splice(0)) {
+      this._ws.send(data, { binary: typeof data !== "string" }, () => {
+        this.bufferedAmount -= length;
+      });
+    }
+  }
+
+  _scheduleSend() {
+    if (this._dequeueScheduled) {
+      return;
+    }
+    this._dequeueScheduled = true;
+    process.nextTick(() => {
+      this._dequeueScheduled = false;
+      this._actuallySend();
+    });
+  }
+}
+
+setupForSimpleEventAccessors(WebSocketImpl.prototype, ["open", "message", "error", "close"]);
+
+exports.implementation = WebSocketImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/webstorage/Storage-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/webstorage/Storage-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/webstorage/Storage-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,102 @@
+"use strict";
+
+const DOMException = require("domexception/webidl2js-wrapper");
+const StorageEvent = require("../generated/StorageEvent");
+const idlUtils = require("../generated/utils");
+const { fireAnEvent } = require("../helpers/events");
+
+// https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-interface
+class StorageImpl {
+  constructor(globalObject, args, privateData) {
+    const { associatedWindow, storageArea, url, type, storageQuota } = privateData;
+
+    this._associatedWindow = associatedWindow;
+    this._items = storageArea;
+    this._url = url;
+    this._type = type;
+    this._quota = storageQuota;
+
+    this._globalObject = globalObject;
+  }
+
+  _dispatchStorageEvent(key, oldValue, newValue) {
+    return this._associatedWindow._currentOriginData.windowsInSameOrigin
+      .filter(target => target !== this._associatedWindow)
+      .forEach(target => fireAnEvent("storage", target, StorageEvent, {
+        key,
+        oldValue,
+        newValue,
+        url: this._url,
+        storageArea: target["_" + this._type]
+      }));
+  }
+
+  get length() {
+    return this._items.size;
+  }
+
+  key(n) {
+    if (n >= this._items.size) {
+      return null;
+    }
+    return [...this._items.keys()][n];
+  }
+
+  getItem(key) {
+    if (this._items.has(key)) {
+      return this._items.get(key);
+    }
+    return null;
+  }
+
+  setItem(key, value) {
+    const oldValue = this._items.get(key) || null;
+
+    if (oldValue === value) {
+      return;
+    }
+
+    // Concatenate all keys and values to measure their length against the quota
+    let itemsTotalLength = key.length + value.length;
+    for (const [curKey, curValue] of this._items) {
+      // If the key already exists, skip it as it will be set to the new value instead
+      if (key !== curKey) {
+        itemsTotalLength += curKey.length + curValue.length;
+      }
+    }
+    if (itemsTotalLength > this._quota) {
+      throw DOMException.create(this._globalObject, [
+        `The ${this._quota}-code unit storage quota has been exceeded.`,
+        "QuotaExceededError"
+      ]);
+    }
+
+    setTimeout(this._dispatchStorageEvent.bind(this), 0, key, oldValue, value);
+
+    this._items.set(key, value);
+  }
+
+  removeItem(key) {
+    if (this._items.has(key)) {
+      setTimeout(this._dispatchStorageEvent.bind(this), 0, key, this._items.get(key), null);
+
+      this._items.delete(key);
+    }
+  }
+
+  clear() {
+    if (this._items.size > 0) {
+      setTimeout(this._dispatchStorageEvent.bind(this), 0, null, null, null);
+
+      this._items.clear();
+    }
+  }
+
+  get [idlUtils.supportedPropertyNames]() {
+    return this._items.keys();
+  }
+}
+
+module.exports = {
+  implementation: StorageImpl
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/BarProp-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/BarProp-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/BarProp-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,10 @@
+"use strict";
+
+// https://html.spec.whatwg.org/multipage/window-object.html#browser-interface-elements
+class BarPropImpl {}
+
+// Since many BarProps do not apply to modern browsers,
+// returning true in all cases seems to be common practice.
+BarPropImpl.prototype.visible = true;
+
+exports.implementation = BarPropImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/External-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/External-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/External-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,9 @@
+"use strict";
+
+// https://html.spec.whatwg.org/multipage/obsolete.html#dom-external
+exports.implementation = class ExternalImpl {
+  // The AddSearchProvider() and IsSearchProviderInstalled() methods must do nothing
+  AddSearchProvider() {}
+
+  IsSearchProviderInstalled() {}
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/History-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/History-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/History-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,134 @@
+"use strict";
+const DOMException = require("domexception/webidl2js-wrapper");
+const { documentBaseURLSerialized, parseURLToResultingURLRecord } = require("../helpers/document-base-url.js");
+
+// https://html.spec.whatwg.org/#history-3
+exports.implementation = class HistoryImpl {
+  constructor(globalObject, args, privateData) {
+    this._window = privateData.window;
+    this._document = privateData.document;
+    this._actAsIfLocationReloadCalled = privateData.actAsIfLocationReloadCalled;
+    this._state = null;
+
+    this._globalObject = globalObject;
+  }
+
+  _guardAgainstInactiveDocuments() {
+    if (!this._window) {
+      throw DOMException.create(this._globalObject, [
+        "History object is associated with a document that is not fully active.",
+        "SecurityError"
+      ]);
+    }
+  }
+
+  get length() {
+    this._guardAgainstInactiveDocuments();
+
+    return this._window._sessionHistory.length;
+  }
+
+  get state() {
+    this._guardAgainstInactiveDocuments();
+
+    return this._state;
+  }
+
+  go(delta) {
+    this._guardAgainstInactiveDocuments();
+
+    if (delta === 0) {
+      // When the go(delta) method is invoked, if delta is zero, the user agent must act as
+      // if the location.reload() method was called instead.
+      this._actAsIfLocationReloadCalled();
+    } else {
+      // Otherwise, the user agent must traverse the history by a delta whose value is delta
+      this._window._sessionHistory.traverseByDelta(delta);
+    }
+  }
+
+  back() {
+    this.go(-1);
+  }
+
+  forward() {
+    this.go(+1);
+  }
+
+  pushState(data, title, url) {
+    this._sharedPushAndReplaceState(data, title, url, "pushState");
+  }
+  replaceState(data, title, url) {
+    this._sharedPushAndReplaceState(data, title, url, "replaceState");
+  }
+
+  // https://html.spec.whatwg.org/#dom-history-pushstate
+  _sharedPushAndReplaceState(data, title, url, methodName) {
+    this._guardAgainstInactiveDocuments();
+
+    // TODO structured clone data
+
+    let newURL;
+    if (url !== null) {
+      // Not implemented: use of entry settings object's API base URL. Instead we just use the document base URL. The
+      // difference matters in the case of cross-frame calls.
+      newURL = parseURLToResultingURLRecord(url, this._document);
+
+      if (newURL === null) {
+        throw DOMException.create(this._globalObject, [
+          `Could not parse url argument "${url}" to ${methodName} against base URL ` +
+          `"${documentBaseURLSerialized(this._document)}".`,
+          "SecurityError"
+        ]);
+      }
+
+      if (newURL.scheme !== this._document._URL.scheme ||
+          newURL.username !== this._document._URL.username ||
+          newURL.password !== this._document._URL.password ||
+          newURL.host !== this._document._URL.host ||
+          newURL.port !== this._document._URL.port ||
+          newURL.cannotBeABaseURL !== this._document._URL.cannotBeABaseURL) {
+        throw DOMException.create(this._globalObject, [
+          `${methodName} cannot update history to a URL which differs in components other than in ` +
+          `path, query, or fragment.`,
+          "SecurityError"
+        ]);
+      }
+
+      // Not implemented: origin check (seems to only apply to documents with weird origins, e.g. sandboxed ones)
+    } else {
+      newURL = this._window._sessionHistory.currentEntry.url;
+    }
+
+    if (methodName === "pushState") {
+      this._window._sessionHistory.removeAllEntriesAfterCurrentEntry();
+
+      this._window._sessionHistory.clearHistoryTraversalTasks();
+
+      const newEntry = {
+        document: this._document,
+        stateObject: data,
+        title,
+        url: newURL
+      };
+      this._window._sessionHistory.addEntryAfterCurrentEntry(newEntry);
+      this._window._sessionHistory.updateCurrentEntry(newEntry);
+    } else {
+      const { currentEntry } = this._window._sessionHistory;
+      currentEntry.stateObject = data;
+      currentEntry.title = title;
+      currentEntry.url = newURL;
+    }
+
+    // TODO: If the current entry in the session history represents a non-GET request
+    // (e.g. it was the result of a POST submission) then update it to instead represent
+    // a GET request.
+
+    this._document._URL = newURL;
+
+    // arguably it's a bit odd that the state and latestEntry do not belong to the SessionHistory
+    // but the spec gives them to "History" and "Document" respecively.
+    this._state = data; // TODO clone again!! O_o
+    this._document._latestEntry = this._window._sessionHistory.currentEntry;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/Location-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,238 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { documentBaseURL, parseURLToResultingURLRecord } = require("../helpers/document-base-url");
+const { navigate } = require("./navigation");
+
+// Not implemented: use of entry settings object's API base URL in href setter, assign, and replace. Instead we just
+// use the document base URL. The difference matters in the case of cross-frame calls.
+
+exports.implementation = class LocationImpl {
+  constructor(globalObject, args, privateData) {
+    this._relevantDocument = privateData.relevantDocument;
+    this.url = null;
+
+    this._globalObject = globalObject;
+  }
+
+  get _url() {
+    return this._relevantDocument._URL;
+  }
+
+  _locationObjectSetterNavigate(url) {
+    // Not implemented: extra steps here to determine replacement flag.
+
+    return this._locationObjectNavigate(url);
+  }
+
+  _locationObjectNavigate(url, { replacement = false } = {}) {
+    // Not implemented: the setup for calling navigate, which doesn't apply to our stub navigate anyway.
+
+    navigate(this._relevantDocument._defaultView, url, { replacement, exceptionsEnabled: true });
+  }
+
+  toString() {
+    return this.href;
+  }
+
+  get href() {
+    return whatwgURL.serializeURL(this._url);
+  }
+  set href(v) {
+    const newURL = whatwgURL.parseURL(v, { baseURL: documentBaseURL(this._relevantDocument) });
+    if (newURL === null) {
+      throw new TypeError(`Could not parse "${v}" as a URL`);
+    }
+
+    this._locationObjectSetterNavigate(newURL);
+  }
+
+  get origin() {
+    return whatwgURL.serializeURLOrigin(this._url);
+  }
+
+  get protocol() {
+    return this._url.scheme + ":";
+  }
+  set protocol(v) {
+    const copyURL = { ...this._url };
+
+    const possibleFailure = whatwgURL.basicURLParse(v + ":", { url: copyURL, stateOverride: "scheme start" });
+    if (possibleFailure === null) {
+      throw new TypeError(`Could not parse the URL after setting the procol to "${v}"`);
+    }
+
+    if (copyURL.scheme !== "http" && copyURL.scheme !== "https") {
+      return;
+    }
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  get host() {
+    const url = this._url;
+
+    if (url.host === null) {
+      return "";
+    }
+    if (url.port === null) {
+      return whatwgURL.serializeHost(url.host);
+    }
+
+    return whatwgURL.serializeHost(url.host) + ":" + whatwgURL.serializeInteger(url.port);
+  }
+  set host(v) {
+    const copyURL = { ...this._url };
+
+    if (copyURL.cannotBeABaseURL) {
+      return;
+    }
+
+    whatwgURL.basicURLParse(v, { url: copyURL, stateOverride: "host" });
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  get hostname() {
+    if (this._url.host === null) {
+      return "";
+    }
+
+    return whatwgURL.serializeHost(this._url.host);
+  }
+  set hostname(v) {
+    const copyURL = { ...this._url };
+
+    if (copyURL.cannotBeABaseURL) {
+      return;
+    }
+
+    whatwgURL.basicURLParse(v, { url: copyURL, stateOverride: "hostname" });
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  get port() {
+    if (this._url.port === null) {
+      return "";
+    }
+
+    return whatwgURL.serializeInteger(this._url.port);
+  }
+  set port(v) {
+    const copyURL = { ...this._url };
+
+    if (copyURL.host === null || copyURL.cannotBeABaseURL || copyURL.scheme === "file") {
+      return;
+    }
+
+    whatwgURL.basicURLParse(v, { url: copyURL, stateOverride: "port" });
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  get pathname() {
+    const url = this._url;
+
+    if (url.cannotBeABaseURL) {
+      return url.path[0];
+    }
+
+    return "/" + url.path.join("/");
+  }
+  set pathname(v) {
+    const copyURL = { ...this._url };
+
+    if (copyURL.cannotBeABaseURL) {
+      return;
+    }
+
+    copyURL.path = [];
+    whatwgURL.basicURLParse(v, { url: copyURL, stateOverride: "path start" });
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  get search() {
+    if (this._url.query === null || this._url.query === "") {
+      return "";
+    }
+
+    return "?" + this._url.query;
+  }
+  set search(v) {
+    const copyURL = { ...this._url };
+
+    if (v === "") {
+      copyURL.query = null;
+    } else {
+      const input = v[0] === "?" ? v.substring(1) : v;
+      copyURL.query = "";
+      whatwgURL.basicURLParse(input, {
+        url: copyURL,
+        stateOverride: "query",
+        encodingOverride: this._relevantDocument.charset
+      });
+    }
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  get hash() {
+    if (this._url.fragment === null || this._url.fragment === "") {
+      return "";
+    }
+
+    return "#" + this._url.fragment;
+  }
+  set hash(v) {
+    const copyURL = { ...this._url };
+
+    if (copyURL.scheme === "javascript") {
+      return;
+    }
+
+    if (v === "") {
+      copyURL.fragment = null;
+    } else {
+      const input = v[0] === "#" ? v.substring(1) : v;
+      copyURL.fragment = "";
+      whatwgURL.basicURLParse(input, { url: copyURL, stateOverride: "fragment" });
+    }
+
+    this._locationObjectSetterNavigate(copyURL);
+  }
+
+  assign(url) {
+    // Should be entry settings object; oh well
+    const parsedURL = parseURLToResultingURLRecord(url, this._relevantDocument);
+
+    if (parsedURL === null) {
+      throw DOMException.create(this._globalObject, [
+        `Could not resolve the given string "${url}" relative to the base URL "${this._relevantDocument.URL}"`,
+        "SyntaxError"
+      ]);
+    }
+
+    this._locationObjectNavigate(parsedURL);
+  }
+
+  replace(url) {
+    // Should be entry settings object; oh well
+    const parsedURL = parseURLToResultingURLRecord(url, this._relevantDocument);
+
+    if (parsedURL === null) {
+      throw DOMException.create(this._globalObject, [
+        `Could not resolve the given string "${url}" relative to the base URL "${this._relevantDocument.URL}"`,
+        "SyntaxError"
+      ]);
+    }
+
+    this._locationObjectNavigate(parsedURL, { replacement: true });
+  }
+
+  reload() {
+    const flags = { replace: true, reloadTriggered: true, exceptionsEnabled: true };
+    navigate(this._relevantDocument._defaultView, this._url, flags);
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/Screen-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/Screen-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/Screen-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,13 @@
+"use strict";
+
+// https://drafts.csswg.org/cssom-view-1/#the-screen-interface
+class ScreenImpl {}
+
+ScreenImpl.prototype.availWidth = 0;
+ScreenImpl.prototype.availHeight = 0;
+ScreenImpl.prototype.width = 0;
+ScreenImpl.prototype.height = 0;
+ScreenImpl.prototype.colorDepth = 24;
+ScreenImpl.prototype.pixelDepth = 24;
+
+exports.implementation = ScreenImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/SessionHistory.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/SessionHistory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/SessionHistory.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,163 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const HashChangeEvent = require("../generated/HashChangeEvent.js");
+const PopStateEvent = require("../generated/PopStateEvent.js");
+const notImplemented = require("../../browser/not-implemented.js");
+const idlUtils = require("../generated/utils.js");
+const { fireAnEvent } = require("../helpers/events");
+
+// https://html.spec.whatwg.org/#session-history
+class SessionHistory {
+  constructor(initialEntry, window) {
+    this._window = window;
+    this._windowImpl = idlUtils.implForWrapper(window);
+    this._historyTraversalQueue = new Set();
+    this._entries = [initialEntry];
+    this._currentIndex = 0;
+  }
+
+  _queueHistoryTraversalTask(fn) {
+    const timeoutId = this._window.setTimeout(() => {
+      this._historyTraversalQueue.delete(timeoutId);
+      fn();
+    }, 0);
+
+    this._historyTraversalQueue.add(timeoutId);
+  }
+
+  clearHistoryTraversalTasks() {
+    for (const timeoutId of this._historyTraversalQueue) {
+      this._window.clearTimeout(timeoutId);
+    }
+    this._historyTraversalQueue.clear();
+  }
+
+  get length() {
+    return this._entries.length;
+  }
+
+  get currentEntry() {
+    return this._entries[this._currentIndex];
+  }
+
+  // https://html.spec.whatwg.org/#dom-history-pushstate
+  removeAllEntriesAfterCurrentEntry() {
+    this._entries.splice(this._currentIndex + 1, Infinity);
+  }
+
+  // https://html.spec.whatwg.org/#traverse-the-history-by-a-delta
+  traverseByDelta(delta) {
+    this._queueHistoryTraversalTask(() => {
+      const newIndex = this._currentIndex + delta;
+      if (newIndex < 0 || newIndex >= this.length) {
+        return;
+      }
+
+      const specifiedEntry = this._entries[newIndex];
+
+      // Not implemented: unload a document guard
+
+      // Not clear that this should be queued. html/browsers/history/the-history-interface/004.html can be fixed
+      // by removing the queue, but doing so breaks some tests in history.js that also pass in browsers.
+      this._queueHistoryTraversalTask(() => {
+        // If there is an ongoing attempt to navigate specified browsing context that has not yet matured,
+        // then cancel that attempt to navigate the browsing context.
+
+        // Doing this seems to break tests involving navigating via push/pop state and via fragments. I think this
+        // is because these navigations should already count as having "matured" because the document is not changing.
+
+        // this.clearHistoryTraversalTasks();
+
+        if (specifiedEntry.document !== this.currentEntry.document) {
+          // TODO: unload the active document with the recycle parameter set to false
+          notImplemented("Traversing history in a way that would change the window", this._window);
+        }
+        this.traverseHistory(specifiedEntry);
+      });
+    });
+  }
+
+  // https://html.spec.whatwg.org/#traverse-the-history
+  traverseHistory(specifiedEntry, flags = {}) {
+    if (!specifiedEntry.document) {
+      // If entry no longer holds a Document object, then navigate the browsing context to entry's URL
+      // to perform an entry update of entry, and abort these steps
+      notImplemented("Traversing the history to an entry that no longer holds a Document object", this._window);
+    }
+    // Not spec compliant, just minimal. Lots of missing steps.
+
+    const nonBlockingEvents = Boolean(flags.nonBlockingEvents);
+
+    const document = idlUtils.implForWrapper(this._window._document);
+
+    const { currentEntry } = this;
+
+    // If the current entry's title was not set by the pushState() or replaceState() methods, then set its title
+    // to the value returned by the document.title IDL attribute.
+    if (currentEntry.title === undefined) {
+      currentEntry.title = document.title;
+    }
+
+
+    if (specifiedEntry.document !== currentEntry.document) {
+      // If entry has a different Document object than the current entry, then...
+      notImplemented("Traversing the history to an entry with a different Document", this._window);
+    }
+
+    document._URL = specifiedEntry.url;
+
+    const hashChanged =
+      specifiedEntry.url.fragment !== currentEntry.url.fragment && specifiedEntry.document === currentEntry.document;
+    let oldURL, newURL;
+    if (hashChanged) {
+      oldURL = currentEntry.url;
+      newURL = specifiedEntry.url;
+    }
+
+    if (flags.replacement) {
+      // If the traversal was initiated with replacement enabled, remove the entry immediately before the
+      // specified entry in the session history.
+      this._entries.splice(this._entries.indexOf(specifiedEntry) - 1, 1);
+    }
+
+    this.updateCurrentEntry(specifiedEntry);
+
+    const state = specifiedEntry.stateObject; // TODO structured clone
+
+    // arguably it's a bit odd that the state and latestEntry do not belong to the SessionHistory
+    // but the spec gives them to "History" and "Document" respecively.
+    document._history._state = state;
+    const stateChanged = specifiedEntry.document._latestEntry !== specifiedEntry;
+    specifiedEntry.document._latestEntry = specifiedEntry;
+
+    const fireEvents = () => this._fireEvents(stateChanged, hashChanged, state, oldURL, newURL);
+
+    if (nonBlockingEvents) {
+      this._window.setTimeout(fireEvents, 0);
+    } else {
+      fireEvents();
+    }
+  }
+
+  _fireEvents(stateChanged, hashChanged, state, oldURL, newURL) {
+    if (stateChanged) {
+      fireAnEvent("popstate", this._windowImpl, PopStateEvent, { state });
+    }
+
+    if (hashChanged) {
+      fireAnEvent("hashchange", this._windowImpl, HashChangeEvent, {
+        oldURL: whatwgURL.serializeURL(oldURL),
+        newURL: whatwgURL.serializeURL(newURL)
+      });
+    }
+  }
+
+  addEntryAfterCurrentEntry(entry) {
+    this._entries.splice(this._currentIndex + 1, 0, entry);
+  }
+
+  updateCurrentEntry(entry) {
+    this._currentIndex = this._entries.indexOf(entry);
+  }
+}
+module.exports = SessionHistory;
Index: frontend/node_modules/jsdom/lib/jsdom/living/window/navigation.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/window/navigation.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/window/navigation.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,84 @@
+"use strict";
+const whatwgURL = require("whatwg-url");
+const notImplemented = require("../../browser/not-implemented.js");
+const reportException = require("../helpers/runtime-script-errors.js");
+const idlUtils = require("../generated/utils.js");
+
+exports.evaluateJavaScriptURL = (window, urlRecord) => {
+  const urlString = whatwgURL.serializeURL(urlRecord);
+  const scriptSource = whatwgURL.percentDecode(Buffer.from(urlString)).toString();
+  if (window._runScripts === "dangerously") {
+    try {
+      return window.eval(scriptSource);
+    } catch (e) {
+      reportException(window, e, urlString);
+    }
+  }
+  return undefined;
+};
+
+// https://html.spec.whatwg.org/#navigating-across-documents
+exports.navigate = (window, newURL, flags) => {
+  // This is NOT a spec-compliant implementation of navigation in any way. It implements a few selective steps that
+  // are nice for jsdom users, regarding hash changes and JavaScript URLs. Full navigation support is being worked on
+  // and will likely require some additional hooks to be implemented.
+  if (!window._document) {
+    return;
+  }
+
+  const document = idlUtils.implForWrapper(window._document);
+  const currentURL = document._URL;
+
+  if (!flags.reloadTriggered && urlEquals(currentURL, newURL, { excludeFragments: true })) {
+    if (newURL.fragment !== currentURL.fragment) {
+      navigateToFragment(window, newURL, flags);
+    }
+    return;
+  }
+
+  // NOT IMPLEMENTED: Prompt to unload the active document of browsingContext.
+
+  // NOT IMPLEMENTED: form submission algorithm
+  // const navigationType = 'other';
+
+  // NOT IMPLEMENTED: if resource is a response...
+  if (newURL.scheme === "javascript") {
+    setTimeout(() => {
+      const result = exports.evaluateJavaScriptURL(window, newURL);
+      if (typeof result === "string") {
+        notImplemented("string results from 'javascript:' URLs", window);
+      }
+    }, 0);
+    return;
+  }
+  navigateFetch(window);
+};
+
+// https://html.spec.whatwg.org/#scroll-to-fragid
+function navigateToFragment(window, newURL, flags) {
+  const document = idlUtils.implForWrapper(window._document);
+
+  window._sessionHistory.clearHistoryTraversalTasks();
+
+  if (!flags.replacement) {
+    // handling replacement=true here deviates from spec, but matches real browser behaviour
+    // see https://github.com/whatwg/html/issues/2796 for spec bug
+    window._sessionHistory.removeAllEntriesAfterCurrentEntry();
+  }
+  const newEntry = { document, url: newURL };
+  window._sessionHistory.addEntryAfterCurrentEntry(newEntry);
+  window._sessionHistory.traverseHistory(newEntry, { nonBlockingEvents: true, replacement: flags.replacement });
+}
+
+// https://html.spec.whatwg.org/#process-a-navigate-fetch
+function navigateFetch(window) {
+  // TODO:
+  notImplemented("navigation (except hash changes)", window);
+}
+
+// https://url.spec.whatwg.org/#concept-url-equals
+function urlEquals(a, b, flags) {
+  const serializedA = whatwgURL.serializeURL(a, flags.excludeFragments);
+  const serializedB = whatwgURL.serializeURL(b, flags.excludeFragments);
+  return serializedA === serializedB;
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/xhr/FormData-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/xhr/FormData-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/xhr/FormData-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,171 @@
+"use strict";
+const idlUtils = require("../generated/utils");
+const { closest } = require("../helpers/traversal");
+const { isDisabled, isSubmittable, isButton } = require("../helpers/form-controls");
+const Blob = require("../generated/Blob.js");
+const File = require("../generated/File.js");
+const conversions = require("webidl-conversions");
+
+exports.implementation = class FormDataImpl {
+  constructor(globalObject, args) {
+    this._globalObject = globalObject;
+    this._entries = [];
+
+    if (args[0] !== undefined) {
+      this._entries = constructTheEntryList(args[0]);
+    }
+  }
+
+  append(name, value, filename) {
+    const entry = createAnEntry(name, value, filename);
+    this._entries.push(entry);
+  }
+
+  delete(name) {
+    this._entries = this._entries.filter(entry => entry.name !== name);
+  }
+
+  get(name) {
+    const foundEntry = this._entries.find(entry => entry.name === name);
+    return foundEntry !== undefined ? idlUtils.tryWrapperForImpl(foundEntry.value) : null;
+  }
+
+  getAll(name) {
+    return this._entries.filter(entry => entry.name === name).map(entry => idlUtils.tryWrapperForImpl(entry.value));
+  }
+
+  has(name) {
+    return this._entries.findIndex(entry => entry.name === name) !== -1;
+  }
+
+  set(name, value, filename) {
+    const entry = createAnEntry(name, value, filename);
+
+    const foundIndex = this._entries.findIndex(e => e.name === name);
+    if (foundIndex !== -1) {
+      this._entries[foundIndex] = entry;
+      this._entries = this._entries.filter((e, i) => e.name !== name || i === foundIndex);
+    } else {
+      this._entries.push(entry);
+    }
+  }
+
+  * [Symbol.iterator]() {
+    for (const entry of this._entries) {
+      yield [entry.name, idlUtils.tryWrapperForImpl(entry.value)];
+    }
+  }
+};
+
+function createAnEntry(name, value, filename) {
+  const entry = { name };
+
+  // https://github.com/whatwg/xhr/issues/75
+
+  if (Blob.isImpl(value) && !File.isImpl(value)) {
+    const oldValue = value;
+    value = File.createImpl(value._globalObject, [
+      [],
+      "blob",
+      { type: oldValue.type }
+    ]);
+    // "representing the same bytes"
+    value._buffer = oldValue._buffer;
+  }
+
+  if (File.isImpl(value) && filename !== undefined) {
+    const oldValue = value;
+    value = File.createImpl(value._globalObject, [
+      [],
+      filename,
+      // spec makes no mention of `lastModified`; assume it is inherited
+      // (Chrome's behavior)
+      { type: oldValue.type, lastModified: oldValue.lastModified }
+    ]);
+    // "representing the same bytes"
+    value._buffer = oldValue._buffer;
+  }
+
+  entry.value = value;
+
+  return entry;
+}
+
+function constructTheEntryList(form, submitter) {
+  // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set
+  // TODO: handle encoding
+  // TODO: handling "constructing entry list"
+
+  const controls = form.elements.filter(isSubmittable); // submittable is a subset of listed
+  const entryList = [];
+
+  for (const field of controls) {
+    if (closest(field, "datalist") !== null) {
+      continue;
+    }
+    if (isDisabled(field)) {
+      continue;
+    }
+    if (isButton(field) && field !== submitter) {
+      continue;
+    }
+    if (field.type === "checkbox" && field._checkedness === false) {
+      continue;
+    }
+    if (field.type === "radio" && field._checkedness === false) {
+      continue;
+    }
+    if (field.localName === "object") { // in jsdom, no objects are "using a plugin"
+      continue;
+    }
+
+    // TODO: Handle <input type="image">
+    // TODO: handle form-associated custom elements.
+
+    const name = field.getAttributeNS(null, "name");
+    if (name === null || name === "") {
+      continue;
+    }
+
+    if (field.localName === "select") {
+      for (const option of field.options) {
+        if (option._selectedness === true && !isDisabled(field)) {
+          appendAnEntry(entryList, name, option._getValue());
+        }
+      }
+    } else if (field.localName === "input" && (field.type === "checkbox" || field.type === "radio")) {
+      const value = field.hasAttributeNS(null, "value") ? field.getAttributeNS(null, "value") : "on";
+      appendAnEntry(entryList, name, value);
+    } else if (field.type === "file") {
+      if (field.files.length === 0) {
+        const value = File.createImpl(form._globalObject, [[], "", { type: "application/octet-stream" }]);
+        appendAnEntry(entryList, name, value);
+      } else {
+        for (let i = 0; i < field.files.length; ++i) {
+          appendAnEntry(entryList, name, field.files.item(i));
+        }
+      }
+    } else {
+      appendAnEntry(entryList, name, field._getValue());
+    }
+
+    const dirname = field.getAttributeNS(null, "dirname");
+    if (dirname !== null && dirname !== "") {
+      const dir = "ltr"; // jsdom does not (yet?) implement actual directionality
+      appendAnEntry(entryList, dirname, dir);
+    }
+  }
+
+  // TODO: formdata event
+
+  return entryList;
+}
+
+function appendAnEntry(entryList, name, value) {
+  name = conversions.USVString(name);
+  if (!File.isImpl(value)) {
+    value = conversions.USVString(value);
+  }
+  const entry = createAnEntry(name, value);
+  entryList.push(entry);
+}
Index: frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequest-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,1023 @@
+"use strict";
+
+const HTTP_STATUS_CODES = require("http").STATUS_CODES;
+const { spawnSync } = require("child_process");
+const { URL } = require("whatwg-url");
+const whatwgEncoding = require("whatwg-encoding");
+const tough = require("tough-cookie");
+const MIMEType = require("whatwg-mimetype");
+
+const xhrUtils = require("./xhr-utils");
+const DOMException = require("domexception/webidl2js-wrapper");
+const { documentBaseURLSerialized } = require("../helpers/document-base-url");
+const { asciiCaseInsensitiveMatch } = require("../helpers/strings");
+const idlUtils = require("../generated/utils");
+const Document = require("../generated/Document");
+const Blob = require("../generated/Blob");
+const FormData = require("../generated/FormData");
+const XMLHttpRequestEventTargetImpl = require("./XMLHttpRequestEventTarget-impl").implementation;
+const XMLHttpRequestUpload = require("../generated/XMLHttpRequestUpload");
+const ProgressEvent = require("../generated/ProgressEvent");
+const { isArrayBuffer } = require("../generated/utils");
+const { parseIntoDocument } = require("../../browser/parser");
+const { fragmentSerialization } = require("../domparsing/serialization");
+const { setupForSimpleEventAccessors } = require("../helpers/create-event-accessor");
+const { parseJSONFromBytes } = require("../helpers/json");
+const { fireAnEvent } = require("../helpers/events");
+const { copyToArrayBufferInNewRealm } = require("../helpers/binary-data");
+
+const { READY_STATES } = xhrUtils;
+
+const syncWorkerFile = require.resolve ? require.resolve("./xhr-sync-worker.js") : null;
+
+const tokenRegexp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
+const fieldValueRegexp = /^[ \t]*(?:[\x21-\x7E\x80-\xFF](?:[ \t][\x21-\x7E\x80-\xFF])?)*[ \t]*$/;
+
+const forbiddenRequestHeaders = new Set([
+  "accept-charset",
+  "accept-encoding",
+  "access-control-request-headers",
+  "access-control-request-method",
+  "connection",
+  "content-length",
+  "cookie",
+  "cookie2",
+  "date",
+  "dnt",
+  "expect",
+  "host",
+  "keep-alive",
+  "origin",
+  "referer",
+  "te",
+  "trailer",
+  "transfer-encoding",
+  "upgrade",
+  "via"
+]);
+const forbiddenResponseHeaders = new Set([
+  "set-cookie",
+  "set-cookie2"
+]);
+const uniqueResponseHeaders = new Set([
+  "content-type",
+  "content-length",
+  "user-agent",
+  "referer",
+  "host",
+  "authorization",
+  "proxy-authorization",
+  "if-modified-since",
+  "if-unmodified-since",
+  "from",
+  "location",
+  "max-forwards"
+]);
+const corsSafeResponseHeaders = new Set([
+  "cache-control",
+  "content-language",
+  "content-length",
+  "content-type",
+  "expires",
+  "last-modified",
+  "pragma"
+]);
+
+const allowedRequestMethods = new Set(["OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE"]);
+const forbiddenRequestMethods = new Set(["TRACK", "TRACE", "CONNECT"]);
+
+class XMLHttpRequestImpl extends XMLHttpRequestEventTargetImpl {
+  constructor(window) {
+    super(window);
+
+    // Avoid running `_ownerDocument` getter multiple times in the constructor:
+    const { _ownerDocument } = this;
+
+    this.upload = XMLHttpRequestUpload.createImpl(window);
+
+    this.readyState = READY_STATES.UNSENT;
+    this.responseURL = "";
+    this.status = 0;
+    this.statusText = "";
+
+    this.flag = {
+      synchronous: false,
+      withCredentials: false,
+      mimeType: null,
+      auth: null,
+      method: undefined,
+      responseType: "",
+      requestHeaders: {},
+      referrer: _ownerDocument.URL,
+      uri: "",
+      timeout: 0,
+      body: undefined,
+      formData: false,
+      preflight: false,
+      requestManager: _ownerDocument._requestManager,
+      strictSSL: window._resourceLoader._strictSSL,
+      proxy: window._resourceLoader._proxy,
+      cookieJar: _ownerDocument._cookieJar,
+      encoding: _ownerDocument._encoding,
+      origin: window._origin,
+      userAgent: window.navigator.userAgent
+    };
+
+    this.properties = {
+      beforeSend: false,
+      send: false,
+      client: null,
+
+      timeoutStart: 0,
+      timeoutId: 0,
+      timeoutFn: null,
+
+      responseBuffer: null,
+      responseCache: null,
+      responseTextCache: null,
+      responseXMLCache: null,
+
+      responseHeaders: {},
+      filteredResponseHeaders: [],
+
+      error: "",
+      uploadComplete: false,
+      uploadListener: false,
+
+      // Signifies that we're calling abort() from xhr-utils.js because of a window shutdown.
+      // In that case the termination reason is "fatal", not "end-user abort".
+      abortError: false,
+
+      cookieJar: _ownerDocument._cookieJar,
+      bufferStepSize: 1 * 1024 * 1024, // pre-allocate buffer increase step size. init value is 1MB
+      totalReceivedChunkSize: 0
+    };
+  }
+
+  get responseType() {
+    return this.flag.responseType;
+  }
+  set responseType(responseType) {
+    const { flag } = this;
+    if (this.readyState === READY_STATES.LOADING || this.readyState === READY_STATES.DONE) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+    if (this.readyState === READY_STATES.OPENED && flag.synchronous) {
+      throw DOMException.create(this._globalObject, [
+        "The object does not support the operation or argument.",
+        "InvalidAccessError"
+      ]);
+    }
+    flag.responseType = responseType;
+  }
+
+  get response() {
+    const { properties } = this;
+    if (properties.responseCache) {
+      // Needed because of: https://github.com/jsdom/webidl2js/issues/149
+      return idlUtils.tryWrapperForImpl(properties.responseCache);
+    }
+    let res;
+
+    const responseBuffer = properties.responseBuffer ?
+      properties.responseBuffer.slice(0, properties.totalReceivedChunkSize) :
+      null;
+
+    switch (this.responseType) {
+      case "":
+      case "text": {
+        res = this.responseText;
+        break;
+      }
+      case "arraybuffer": {
+        if (!responseBuffer) {
+          return null;
+        }
+        res = copyToArrayBufferInNewRealm(responseBuffer, this._globalObject);
+        break;
+      }
+      case "blob": {
+        if (!responseBuffer) {
+          return null;
+        }
+        const contentType = finalMIMEType(this);
+        res = Blob.createImpl(this._globalObject, [
+          [new Uint8Array(responseBuffer)],
+          { type: contentType || "" }
+        ]);
+        break;
+      }
+      case "document": {
+        res = this.responseXML;
+        break;
+      }
+      case "json": {
+        if (this.readyState !== READY_STATES.DONE || !responseBuffer) {
+          res = null;
+        }
+
+        try {
+          res = parseJSONFromBytes(responseBuffer);
+        } catch (e) {
+          res = null;
+        }
+        break;
+      }
+    }
+    properties.responseCache = res;
+    // Needed because of: https://github.com/jsdom/webidl2js/issues/149
+    return idlUtils.tryWrapperForImpl(res);
+  }
+  get responseText() {
+    const { properties } = this;
+    if (this.responseType !== "" && this.responseType !== "text") {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+    if (this.readyState !== READY_STATES.LOADING && this.readyState !== READY_STATES.DONE) {
+      return "";
+    }
+    if (properties.responseTextCache) {
+      return properties.responseTextCache;
+    }
+    const responseBuffer = properties.responseBuffer ?
+      properties.responseBuffer.slice(0, properties.totalReceivedChunkSize) :
+      null;
+
+    if (!responseBuffer) {
+      return "";
+    }
+
+    const fallbackEncoding = finalCharset(this) || whatwgEncoding.getBOMEncoding(responseBuffer) || "UTF-8";
+    const res = whatwgEncoding.decode(responseBuffer, fallbackEncoding);
+
+    properties.responseTextCache = res;
+    return res;
+  }
+  get responseXML() {
+    const { flag, properties } = this;
+    if (this.responseType !== "" && this.responseType !== "document") {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+    if (this.readyState !== READY_STATES.DONE) {
+      return null;
+    }
+    if (properties.responseXMLCache) {
+      return properties.responseXMLCache;
+    }
+    const responseBuffer = properties.responseBuffer ?
+      properties.responseBuffer.slice(0, properties.totalReceivedChunkSize) :
+      null;
+
+    if (!responseBuffer) {
+      return null;
+    }
+
+    const contentType = finalMIMEType(this);
+    let isHTML = false;
+    let isXML = false;
+    const parsed = MIMEType.parse(contentType);
+    if (parsed) {
+      isHTML = parsed.isHTML();
+      isXML = parsed.isXML();
+      if (!isXML && !isHTML) {
+        return null;
+      }
+    }
+
+    if (this.responseType === "" && isHTML) {
+      return null;
+    }
+
+    const encoding = finalCharset(this) || whatwgEncoding.getBOMEncoding(responseBuffer) || "UTF-8";
+    const resText = whatwgEncoding.decode(responseBuffer, encoding);
+
+    if (!resText) {
+      return null;
+    }
+    const res = Document.createImpl(this._globalObject, [], {
+      options: {
+        url: flag.uri,
+        lastModified: new Date(getResponseHeader(this, "last-modified")),
+        parsingMode: isHTML ? "html" : "xml",
+        cookieJar: { setCookieSync: () => undefined, getCookieStringSync: () => "" },
+        encoding,
+        parseOptions: this._ownerDocument._parseOptions
+      }
+    });
+    try {
+      parseIntoDocument(resText, res);
+    } catch (e) {
+      properties.responseXMLCache = null;
+      return null;
+    }
+    res.close();
+    properties.responseXMLCache = res;
+    return res;
+  }
+
+  get timeout() {
+    return this.flag.timeout;
+  }
+  set timeout(val) {
+    const { flag, properties } = this;
+    if (flag.synchronous) {
+      throw DOMException.create(this._globalObject, [
+        "The object does not support the operation or argument.",
+        "InvalidAccessError"
+      ]);
+    }
+    flag.timeout = val;
+    clearTimeout(properties.timeoutId);
+    if (val > 0 && properties.timeoutFn) {
+      properties.timeoutId = setTimeout(
+        properties.timeoutFn,
+        Math.max(0, val - ((new Date()).getTime() - properties.timeoutStart))
+      );
+    } else {
+      properties.timeoutFn = null;
+      properties.timeoutStart = 0;
+    }
+  }
+
+  get withCredentials() {
+    return this.flag.withCredentials;
+  }
+  set withCredentials(val) {
+    const { flag, properties } = this;
+    if (!(this.readyState === READY_STATES.UNSENT || this.readyState === READY_STATES.OPENED)) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+    if (properties.send) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+    flag.withCredentials = val;
+  }
+
+  abort() {
+    const { properties } = this;
+    // Terminate the request
+    clearTimeout(properties.timeoutId);
+    properties.timeoutFn = null;
+    properties.timeoutStart = 0;
+
+    const { client } = properties;
+    if (client) {
+      client.abort();
+      properties.client = null;
+    }
+
+    if (properties.abortError) {
+      // Special case that ideally shouldn't be going through the public API at all.
+      // Run the https://xhr.spec.whatwg.org/#handle-errors "fatal" steps.
+      this.readyState = READY_STATES.DONE;
+      properties.send = false;
+      xhrUtils.setResponseToNetworkError(this);
+      return;
+    }
+
+    if ((this.readyState === READY_STATES.OPENED && properties.send) ||
+        this.readyState === READY_STATES.HEADERS_RECEIVED ||
+        this.readyState === READY_STATES.LOADING) {
+      xhrUtils.requestErrorSteps(this, "abort");
+    }
+
+    if (this.readyState === READY_STATES.DONE) {
+      this.readyState = READY_STATES.UNSENT;
+
+      xhrUtils.setResponseToNetworkError(this);
+    }
+  }
+  getAllResponseHeaders() {
+    const { properties, readyState } = this;
+    if (readyState === READY_STATES.UNSENT || readyState === READY_STATES.OPENED) {
+      return "";
+    }
+    return Object.keys(properties.responseHeaders)
+      .filter(key => properties.filteredResponseHeaders.indexOf(key) === -1)
+      .map(key => [key.toLowerCase(), properties.responseHeaders[key]].join(": "))
+      .join("\r\n");
+  }
+
+  getResponseHeader(header) {
+    const { properties, readyState } = this;
+    if (readyState === READY_STATES.UNSENT || readyState === READY_STATES.OPENED) {
+      return null;
+    }
+    const lcHeader = header.toLowerCase();
+    if (properties.filteredResponseHeaders.find(filtered => lcHeader === filtered.toLowerCase())) {
+      return null;
+    }
+    return getResponseHeader(this, lcHeader);
+  }
+
+  open(method, uri, asynchronous, user, password) {
+    const { flag, properties, _ownerDocument } = this;
+    if (!_ownerDocument) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    if (!tokenRegexp.test(method)) {
+      throw DOMException.create(this._globalObject, [
+        "The string did not match the expected pattern.",
+        "SyntaxError"
+      ]);
+    }
+    const upperCaseMethod = method.toUpperCase();
+    if (forbiddenRequestMethods.has(upperCaseMethod)) {
+      throw DOMException.create(this._globalObject, ["The operation is insecure.", "SecurityError"]);
+    }
+
+    const { client } = properties;
+    if (client && typeof client.abort === "function") {
+      client.abort();
+    }
+
+    if (allowedRequestMethods.has(upperCaseMethod)) {
+      method = upperCaseMethod;
+    }
+    if (typeof asynchronous !== "undefined") {
+      flag.synchronous = !asynchronous;
+    } else {
+      flag.synchronous = false;
+    }
+    if (flag.responseType && flag.synchronous) {
+      throw DOMException.create(this._globalObject, [
+        "The object does not support the operation or argument.",
+        "InvalidAccessError"
+      ]);
+    }
+    if (flag.synchronous && flag.timeout) {
+      throw DOMException.create(this._globalObject, [
+        "The object does not support the operation or argument.",
+        "InvalidAccessError"
+      ]);
+    }
+    flag.method = method;
+
+    let urlObj;
+    try {
+      urlObj = new URL(uri, documentBaseURLSerialized(_ownerDocument));
+    } catch (e) {
+      throw DOMException.create(this._globalObject, [
+        "The string did not match the expected pattern.",
+        "SyntaxError"
+      ]);
+    }
+
+    if (user || (password && !urlObj.username)) {
+      flag.auth = {
+        user,
+        pass: password
+      };
+      urlObj.username = "";
+      urlObj.password = "";
+    }
+
+    flag.uri = urlObj.href;
+    flag.requestHeaders = {};
+    flag.preflight = false;
+
+    properties.send = false;
+    properties.uploadListener = false;
+    properties.abortError = false;
+    this.responseURL = "";
+    readyStateChange(this, READY_STATES.OPENED);
+  }
+
+  overrideMimeType(mime) {
+    const { readyState } = this;
+    if (readyState === READY_STATES.LOADING || readyState === READY_STATES.DONE) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    this.flag.overrideMIMEType = "application/octet-stream";
+
+    // Waiting for better spec: https://github.com/whatwg/xhr/issues/157
+    const parsed = MIMEType.parse(mime);
+    if (parsed) {
+      this.flag.overrideMIMEType = parsed.essence;
+
+      const charset = parsed.parameters.get("charset");
+      if (charset) {
+        this.flag.overrideCharset = whatwgEncoding.labelToName(charset);
+      }
+    }
+  }
+
+  // TODO: Add support for URLSearchParams and ReadableStream
+  send(body) {
+    const { flag, properties, upload, _ownerDocument } = this;
+    // Not per spec, but per tests: https://github.com/whatwg/xhr/issues/65
+    if (!_ownerDocument) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    if (this.readyState !== READY_STATES.OPENED || properties.send) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    properties.beforeSend = true;
+
+    try {
+      if (flag.method === "GET" || flag.method === "HEAD") {
+        body = null;
+      }
+
+      if (body !== null) {
+        let encoding = null;
+        let mimeType = null;
+
+        if (Document.isImpl(body)) {
+          encoding = "UTF-8";
+          mimeType = (body._parsingMode === "html" ? "text/html" : "application/xml") + ";charset=UTF-8";
+          flag.body = fragmentSerialization(body, { requireWellFormed: false });
+        } else {
+          if (typeof body === "string") {
+            encoding = "UTF-8";
+          }
+          const { buffer, formData, contentType } = extractBody(body);
+          mimeType = contentType;
+          flag.body = buffer || formData;
+          flag.formData = Boolean(formData);
+        }
+
+        const existingContentType = xhrUtils.getRequestHeader(flag.requestHeaders, "content-type");
+        if (mimeType !== null && existingContentType === null) {
+          flag.requestHeaders["Content-Type"] = mimeType;
+        } else if (existingContentType !== null && encoding !== null) {
+          // Waiting for better spec: https://github.com/whatwg/xhr/issues/188. This seems like a good guess at what
+          // the spec will be, in the meantime.
+          const parsed = MIMEType.parse(existingContentType);
+          if (parsed) {
+            const charset = parsed.parameters.get("charset");
+            if (charset && !asciiCaseInsensitiveMatch(charset, encoding) && encoding !== null) {
+              parsed.parameters.set("charset", encoding);
+              xhrUtils.updateRequestHeader(flag.requestHeaders, "content-type", parsed.toString());
+            }
+          }
+        }
+      }
+    } finally {
+      if (properties.beforeSend) {
+        properties.beforeSend = false;
+      } else {
+        throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+      }
+    }
+
+    if (Object.keys(upload._eventListeners).length > 0) {
+      properties.uploadListener = true;
+    }
+
+    // request doesn't like zero-length bodies
+    if (flag.body && flag.body.byteLength === 0) {
+      flag.body = null;
+    }
+
+    if (flag.synchronous) {
+      const flagStr = JSON.stringify(flag, function (k, v) {
+        if (this === flag && k === "requestManager") {
+          return null;
+        }
+        if (this === flag && k === "pool" && v) {
+          return { maxSockets: v.maxSockets };
+        }
+        return v;
+      });
+      const res = spawnSync(
+        process.execPath,
+        [syncWorkerFile],
+        { input: flagStr, maxBuffer: Infinity }
+      );
+      if (res.status !== 0) {
+        throw new Error(res.stderr.toString());
+      }
+      if (res.error) {
+        if (typeof res.error === "string") {
+          res.error = new Error(res.error);
+        }
+        throw res.error;
+      }
+
+      const response = JSON.parse(res.stdout.toString());
+      const resProp = response.properties;
+      if (resProp.responseBuffer && resProp.responseBuffer.data) {
+        resProp.responseBuffer = Buffer.from(resProp.responseBuffer.data);
+      }
+      if (resProp.cookieJar) {
+        resProp.cookieJar = tough.CookieJar.deserializeSync(
+          resProp.cookieJar,
+          _ownerDocument._cookieJar.store
+        );
+      }
+
+      this.readyState = READY_STATES.LOADING;
+      this.status = response.status;
+      this.statusText = response.statusText;
+      this.responseURL = response.responseURL;
+      Object.assign(this.properties, response.properties);
+
+      if (resProp.error) {
+        xhrUtils.dispatchError(this);
+        throw DOMException.create(this._globalObject, [resProp.error, "NetworkError"]);
+      } else {
+        const { responseBuffer } = properties;
+        const contentLength = getResponseHeader(this, "content-length") || "0";
+        const bufferLength = parseInt(contentLength) || responseBuffer.length;
+        const progressObj = { lengthComputable: false };
+        if (bufferLength !== 0) {
+          progressObj.total = bufferLength;
+          progressObj.loaded = bufferLength;
+          progressObj.lengthComputable = true;
+        }
+        fireAnEvent("progress", this, ProgressEvent, progressObj);
+        readyStateChange(this, READY_STATES.DONE);
+        fireAnEvent("load", this, ProgressEvent, progressObj);
+        fireAnEvent("loadend", this, ProgressEvent, progressObj);
+      }
+    } else {
+      properties.send = true;
+
+      fireAnEvent("loadstart", this, ProgressEvent);
+
+      const client = xhrUtils.createClient(this);
+
+      properties.client = client;
+      // For new client, reset totalReceivedChunkSize and bufferStepSize
+      properties.totalReceivedChunkSize = 0;
+      properties.bufferStepSize = 1 * 1024 * 1024;
+
+      properties.origin = flag.origin;
+
+      client.on("error", err => {
+        client.removeAllListeners();
+        properties.error = err;
+        xhrUtils.dispatchError(this);
+      });
+
+      client.on("response", (res, url) => receiveResponse(this, res, url));
+
+      client.on("redirect", (response, requestHeaders, currentURL) => {
+        const destUrlObj = new URL(requestHeaders.Referer);
+        const urlObj = new URL(currentURL);
+
+        if (destUrlObj.origin !== urlObj.origin && destUrlObj.origin !== flag.origin) {
+          properties.origin = "null";
+        }
+
+        requestHeaders.Origin = properties.origin;
+
+        if (flag.origin !== destUrlObj.origin &&
+            destUrlObj.protocol !== "data:") {
+          if (!xhrUtils.validCORSHeaders(this, response, flag, properties, flag.origin)) {
+            return;
+          }
+          if (urlObj.username || urlObj.password) {
+            properties.error = "Userinfo forbidden in cors redirect";
+            xhrUtils.dispatchError(this);
+          }
+        }
+      });
+      if (body !== null && body !== "") {
+        properties.uploadComplete = false;
+        setDispatchProgressEvents(this);
+      } else {
+        properties.uploadComplete = true;
+      }
+      if (this.timeout > 0) {
+        properties.timeoutStart = (new Date()).getTime();
+        properties.timeoutFn = () => {
+          client.abort();
+          if (!(this.readyState === READY_STATES.UNSENT ||
+              (this.readyState === READY_STATES.OPENED && !properties.send) ||
+              this.readyState === READY_STATES.DONE)) {
+            properties.send = false;
+            let stateChanged = false;
+            if (!properties.uploadComplete) {
+              fireAnEvent("progress", upload, ProgressEvent);
+              readyStateChange(this, READY_STATES.DONE);
+              fireAnEvent("timeout", upload, ProgressEvent);
+              fireAnEvent("loadend", upload, ProgressEvent);
+              stateChanged = true;
+            }
+            fireAnEvent("progress", this, ProgressEvent);
+            if (!stateChanged) {
+              readyStateChange(this, READY_STATES.DONE);
+            }
+            fireAnEvent("timeout", this, ProgressEvent);
+            fireAnEvent("loadend", this, ProgressEvent);
+          }
+          this.readyState = READY_STATES.UNSENT;
+        };
+        properties.timeoutId = setTimeout(properties.timeoutFn, this.timeout);
+      }
+    }
+  }
+
+  setRequestHeader(header, value) {
+    const { flag, properties } = this;
+
+    if (this.readyState !== READY_STATES.OPENED || properties.send) {
+      throw DOMException.create(this._globalObject, ["The object is in an invalid state.", "InvalidStateError"]);
+    }
+
+    value = normalizeHeaderValue(value);
+
+    if (!tokenRegexp.test(header) || !fieldValueRegexp.test(value)) {
+      throw DOMException.create(this._globalObject, [
+        "The string did not match the expected pattern.",
+        "SyntaxError"
+      ]);
+    }
+
+    const lcHeader = header.toLowerCase();
+
+    if (forbiddenRequestHeaders.has(lcHeader) || lcHeader.startsWith("sec-") || lcHeader.startsWith("proxy-")) {
+      return;
+    }
+
+    const keys = Object.keys(flag.requestHeaders);
+    let n = keys.length;
+    while (n--) {
+      const key = keys[n];
+      if (key.toLowerCase() === lcHeader) {
+        flag.requestHeaders[key] += ", " + value;
+        return;
+      }
+    }
+    flag.requestHeaders[header] = value;
+  }
+}
+
+setupForSimpleEventAccessors(XMLHttpRequestImpl.prototype, ["readystatechange"]);
+
+function readyStateChange(xhr, readyState) {
+  if (xhr.readyState === readyState) {
+    return;
+  }
+
+  xhr.readyState = readyState;
+
+  fireAnEvent("readystatechange", xhr);
+}
+
+function receiveResponse(xhr, response, currentURL) {
+  const { flag, properties } = xhr;
+  const { rawHeaders, statusCode } = response;
+
+  let byteOffset = 0;
+
+  const headers = {};
+  const filteredResponseHeaders = [];
+  const headerMap = {};
+  const n = Number(rawHeaders.length);
+  for (let i = 0; i < n; i += 2) {
+    const k = rawHeaders[i];
+    const kl = k.toLowerCase();
+    const v = rawHeaders[i + 1];
+    if (uniqueResponseHeaders.has(kl)) {
+      if (headerMap[kl] !== undefined) {
+        delete headers[headerMap[kl]];
+      }
+      headers[k] = v;
+    } else if (headerMap[kl] !== undefined) {
+      headers[headerMap[kl]] += ", " + v;
+    } else {
+      headers[k] = v;
+    }
+    headerMap[kl] = k;
+  }
+
+  const destUrlObj = new URL(currentURL);
+  if (properties.origin !== destUrlObj.origin &&
+      destUrlObj.protocol !== "data:") {
+    if (!xhrUtils.validCORSHeaders(xhr, response, flag, properties, properties.origin)) {
+      return;
+    }
+    const acehStr = response.headers["access-control-expose-headers"];
+    const aceh = new Set(acehStr ? acehStr.trim().toLowerCase().split(xhrUtils.headerListSeparatorRegexp) : []);
+    for (const header in headers) {
+      const lcHeader = header.toLowerCase();
+      if (!corsSafeResponseHeaders.has(lcHeader) && !aceh.has(lcHeader)) {
+        filteredResponseHeaders.push(header);
+      }
+    }
+  }
+
+  for (const header in headers) {
+    const lcHeader = header.toLowerCase();
+    if (forbiddenResponseHeaders.has(lcHeader)) {
+      filteredResponseHeaders.push(header);
+    }
+  }
+
+  xhr.responseURL = destUrlObj.href;
+
+  xhr.status = statusCode;
+  xhr.statusText = response.statusMessage || HTTP_STATUS_CODES[statusCode] || "";
+
+  properties.responseHeaders = headers;
+  properties.filteredResponseHeaders = filteredResponseHeaders;
+
+  const contentLength = getResponseHeader(xhr, "content-length") || "0";
+  const bufferLength = parseInt(contentLength) || 0;
+  const progressObj = { lengthComputable: false };
+  let lastProgressReported;
+  if (bufferLength !== 0) {
+    progressObj.total = bufferLength;
+    progressObj.loaded = 0;
+    progressObj.lengthComputable = true;
+  }
+  // pre-allocate buffer.
+  properties.responseBuffer = Buffer.alloc(properties.bufferStepSize);
+  properties.responseCache = null;
+  properties.responseTextCache = null;
+  properties.responseXMLCache = null;
+  readyStateChange(xhr, READY_STATES.HEADERS_RECEIVED);
+
+  if (!properties.client) {
+    // The request was aborted in reaction to the readystatechange event.
+    return;
+  }
+
+  // Can't use the client since the client gets the post-ungzipping bytes (which can be greater than the
+  // Content-Length).
+  response.on("data", chunk => {
+    byteOffset += chunk.length;
+    progressObj.loaded = byteOffset;
+  });
+
+  properties.client.on("data", chunk => {
+    properties.totalReceivedChunkSize += chunk.length;
+    if (properties.totalReceivedChunkSize >= properties.bufferStepSize) {
+      properties.bufferStepSize *= 2;
+      while (properties.totalReceivedChunkSize >= properties.bufferStepSize) {
+        properties.bufferStepSize *= 2;
+      }
+      const tmpBuf = Buffer.alloc(properties.bufferStepSize);
+      properties.responseBuffer.copy(tmpBuf, 0, 0, properties.responseBuffer.length);
+      properties.responseBuffer = tmpBuf;
+    }
+    chunk.copy(properties.responseBuffer, properties.totalReceivedChunkSize - chunk.length, 0, chunk.length);
+    properties.responseCache = null;
+    properties.responseTextCache = null;
+    properties.responseXMLCache = null;
+
+    if (xhr.readyState === READY_STATES.HEADERS_RECEIVED) {
+      xhr.readyState = READY_STATES.LOADING;
+    }
+    fireAnEvent("readystatechange", xhr);
+
+    if (progressObj.total !== progressObj.loaded || properties.totalReceivedChunkSize === byteOffset) {
+      if (lastProgressReported !== progressObj.loaded) {
+        // This is a necessary check in the gzip case where we can be getting new data from the client, as it
+        // un-gzips, but no new data has been gotten from the response, so we should not fire a progress event.
+        lastProgressReported = progressObj.loaded;
+        fireAnEvent("progress", xhr, ProgressEvent, progressObj);
+      }
+    }
+  });
+  properties.client.on("end", () => {
+    clearTimeout(properties.timeoutId);
+    properties.timeoutFn = null;
+    properties.timeoutStart = 0;
+    properties.client = null;
+    if (lastProgressReported !== progressObj.loaded) {
+      // https://github.com/whatwg/xhr/issues/318
+      fireAnEvent("progress", xhr, ProgressEvent, progressObj);
+    }
+    readyStateChange(xhr, READY_STATES.DONE);
+    fireAnEvent("load", xhr, ProgressEvent, progressObj);
+    fireAnEvent("loadend", xhr, ProgressEvent, progressObj);
+  });
+}
+
+function setDispatchProgressEvents(xhr) {
+  const { properties, upload } = xhr;
+  const { client } = properties;
+
+  let total = 0;
+  let lengthComputable = false;
+  const length = client.headers && parseInt(xhrUtils.getRequestHeader(client.headers, "content-length"));
+  if (length) {
+    total = length;
+    lengthComputable = true;
+  }
+  const initProgress = {
+    lengthComputable,
+    total,
+    loaded: 0
+  };
+
+  if (properties.uploadListener) {
+    fireAnEvent("loadstart", upload, ProgressEvent, initProgress);
+  }
+
+  client.on("request", req => {
+    req.on("response", () => {
+      properties.uploadComplete = true;
+
+      if (!properties.uploadListener) {
+        return;
+      }
+
+      const progress = {
+        lengthComputable,
+        total,
+        loaded: total
+      };
+      fireAnEvent("progress", upload, ProgressEvent, progress);
+      fireAnEvent("load", upload, ProgressEvent, progress);
+      fireAnEvent("loadend", upload, ProgressEvent, progress);
+    });
+  });
+}
+
+function finalMIMEType(xhr) {
+  const { flag } = xhr;
+  return flag.overrideMIMEType || getResponseHeader(xhr, "content-type");
+}
+
+function finalCharset(xhr) {
+  const { flag } = xhr;
+  if (flag.overrideCharset) {
+    return flag.overrideCharset;
+  }
+  const parsedContentType = MIMEType.parse(getResponseHeader(xhr, "content-type"));
+  if (parsedContentType) {
+    return whatwgEncoding.labelToName(parsedContentType.parameters.get("charset"));
+  }
+  return null;
+}
+
+function getResponseHeader(xhr, lcHeader) {
+  const { properties } = xhr;
+  const keys = Object.keys(properties.responseHeaders);
+  let n = keys.length;
+  while (n--) {
+    const key = keys[n];
+    if (key.toLowerCase() === lcHeader) {
+      return properties.responseHeaders[key];
+    }
+  }
+  return null;
+}
+
+function normalizeHeaderValue(value) {
+  return value.replace(/^[\x09\x0A\x0D\x20]+/, "").replace(/[\x09\x0A\x0D\x20]+$/, "");
+}
+
+function extractBody(bodyInit) {
+  // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
+  // except we represent the body as a Node.js Buffer instead,
+  // or a special case for FormData since we want request to handle that. Probably it would be
+  // cleaner (and allow a future without request) if we did the form encoding ourself.
+
+  if (Blob.isImpl(bodyInit)) {
+    return {
+      buffer: bodyInit._buffer,
+      contentType: bodyInit.type === "" ? null : bodyInit.type
+    };
+  } else if (isArrayBuffer(bodyInit)) {
+    return {
+      buffer: Buffer.from(bodyInit),
+      contentType: null
+    };
+  } else if (ArrayBuffer.isView(bodyInit)) {
+    return {
+      buffer: Buffer.from(bodyInit.buffer, bodyInit.byteOffset, bodyInit.byteLength),
+      contentType: null
+    };
+  } else if (FormData.isImpl(bodyInit)) {
+    const formData = [];
+    for (const entry of bodyInit._entries) {
+      let val;
+      if (Blob.isImpl(entry.value)) {
+        const blob = entry.value;
+        val = {
+          name: entry.name,
+          value: blob._buffer,
+          options: {
+            filename: blob.name,
+            contentType: blob.type,
+            knownLength: blob.size
+          }
+        };
+      } else {
+        val = entry;
+      }
+
+      formData.push(val);
+    }
+
+    return { formData };
+  }
+
+  // Must be a string
+  return {
+    buffer: Buffer.from(bodyInit, "utf-8"),
+    contentType: "text/plain;charset=UTF-8"
+  };
+}
+
+exports.implementation = XMLHttpRequestImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequestEventTarget-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequestEventTarget-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequestEventTarget-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,17 @@
+"use strict";
+const EventTargetImpl = require("../events/EventTarget-impl").implementation;
+const idlUtils = require("../generated/utils");
+const { setupForSimpleEventAccessors } = require("../helpers/create-event-accessor");
+
+const events = ["loadstart", "progress", "abort", "error", "load", "timeout", "loadend"];
+
+class XMLHttpRequestEventTargetImpl extends EventTargetImpl {
+  // TODO: remove this when we fix EventTargetImpl to use this._globalObject directly instead of using _ownerDocument.
+  // https://github.com/jsdom/jsdom/issues/2780
+  get _ownerDocument() {
+    return idlUtils.implForWrapper(this._globalObject._document);
+  }
+}
+setupForSimpleEventAccessors(XMLHttpRequestEventTargetImpl.prototype, events);
+
+exports.implementation = XMLHttpRequestEventTargetImpl;
Index: frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequestUpload-impl.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequestUpload-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/xhr/XMLHttpRequestUpload-impl.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,4 @@
+"use strict";
+const XMLHttpRequestEventTargetImpl = require("./XMLHttpRequestEventTarget-impl").implementation;
+
+exports.implementation = class XMLHttpRequestUploadImpl extends XMLHttpRequestEventTargetImpl {};
Index: frontend/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,60 @@
+"use strict";
+/* eslint-disable no-process-exit */
+const util = require("util");
+const { JSDOM } = require("../../../..");
+const { READY_STATES } = require("./xhr-utils");
+const idlUtils = require("../generated/utils");
+const tough = require("tough-cookie");
+
+const dom = new JSDOM();
+const xhr = new dom.window.XMLHttpRequest();
+const xhrImpl = idlUtils.implForWrapper(xhr);
+
+const chunks = [];
+
+process.stdin.on("data", chunk => {
+  chunks.push(chunk);
+});
+
+process.stdin.on("end", () => {
+  const buffer = Buffer.concat(chunks);
+
+  const flag = JSON.parse(buffer.toString());
+  if (flag.body && flag.body.type === "Buffer" && flag.body.data) {
+    flag.body = Buffer.from(flag.body.data);
+  }
+  if (flag.cookieJar) {
+    flag.cookieJar = tough.CookieJar.fromJSON(flag.cookieJar);
+  }
+
+  flag.synchronous = false;
+  Object.assign(xhrImpl.flag, flag);
+  const { properties } = xhrImpl;
+  xhrImpl.readyState = READY_STATES.OPENED;
+  try {
+    xhr.addEventListener("loadend", () => {
+      if (properties.error) {
+        properties.error = properties.error.stack || util.inspect(properties.error);
+      }
+      process.stdout.write(JSON.stringify({
+        responseURL: xhrImpl.responseURL,
+        status: xhrImpl.status,
+        statusText: xhrImpl.statusText,
+        properties
+      }), () => {
+        process.exit(0);
+      });
+    }, false);
+    xhr.send(flag.body);
+  } catch (error) {
+    properties.error += error.stack || util.inspect(error);
+    process.stdout.write(JSON.stringify({
+      responseURL: xhrImpl.responseURL,
+      status: xhrImpl.status,
+      statusText: xhrImpl.statusText,
+      properties
+    }), () => {
+      process.exit(0);
+    });
+  }
+});
Index: frontend/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/living/xhr/xhr-utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,438 @@
+"use strict";
+const fs = require("fs");
+const { EventEmitter } = require("events");
+const { URL } = require("whatwg-url");
+const parseDataURL = require("data-urls");
+const DOMException = require("domexception/webidl2js-wrapper");
+
+const ProgressEvent = require("../generated/ProgressEvent");
+
+const agentFactory = require("../helpers/agent-factory");
+const Request = require("../helpers/http-request");
+const FormData = require("form-data");
+const { fireAnEvent } = require("../helpers/events");
+
+const headerListSeparatorRegexp = /,[ \t]*/;
+const simpleMethods = new Set(["GET", "HEAD", "POST"]);
+const simpleHeaders = new Set(["accept", "accept-language", "content-language", "content-type"]);
+const preflightHeaders = new Set([
+  "access-control-expose-headers",
+  "access-control-allow-headers",
+  "access-control-allow-credentials",
+  "access-control-allow-origin"
+]);
+
+const READY_STATES = exports.READY_STATES = Object.freeze({
+  UNSENT: 0,
+  OPENED: 1,
+  HEADERS_RECEIVED: 2,
+  LOADING: 3,
+  DONE: 4
+});
+
+function getRequestHeader(requestHeaders, header) {
+  const lcHeader = header.toLowerCase();
+  const keys = Object.keys(requestHeaders);
+  let n = keys.length;
+  while (n--) {
+    const key = keys[n];
+    if (key.toLowerCase() === lcHeader) {
+      return requestHeaders[key];
+    }
+  }
+  return null;
+}
+
+function updateRequestHeader(requestHeaders, header, newValue) {
+  const lcHeader = header.toLowerCase();
+  const keys = Object.keys(requestHeaders);
+  let n = keys.length;
+  while (n--) {
+    const key = keys[n];
+    if (key.toLowerCase() === lcHeader) {
+      requestHeaders[key] = newValue;
+    }
+  }
+}
+
+function dispatchError(xhr) {
+  const errMessage = xhr.properties.error;
+  requestErrorSteps(xhr, "error", DOMException.create(xhr._globalObject, [errMessage, "NetworkError"]));
+
+  if (xhr._ownerDocument) {
+    const error = new Error(errMessage);
+    error.type = "XMLHttpRequest"; // TODO this should become "resource loading" when XHR goes through resource loader
+
+    xhr._ownerDocument._defaultView._virtualConsole.emit("jsdomError", error);
+  }
+}
+
+function validCORSHeaders(xhr, response, flag, properties, origin) {
+  const acaoStr = response.headers["access-control-allow-origin"];
+  const acao = acaoStr ? acaoStr.trim() : null;
+  if (acao !== "*" && acao !== origin) {
+    properties.error = "Cross origin " + origin + " forbidden";
+    dispatchError(xhr);
+    return false;
+  }
+  const acacStr = response.headers["access-control-allow-credentials"];
+  const acac = acacStr ? acacStr.trim() : null;
+  if (flag.withCredentials && acac !== "true") {
+    properties.error = "Credentials forbidden";
+    dispatchError(xhr);
+    return false;
+  }
+  return true;
+}
+
+function validCORSPreflightHeaders(xhr, response, flag, properties) {
+  if (!validCORSHeaders(xhr, response, flag, properties, properties.origin)) {
+    return false;
+  }
+  const acahStr = response.headers["access-control-allow-headers"];
+  const acah = new Set(acahStr ? acahStr.trim().toLowerCase().split(headerListSeparatorRegexp) : []);
+  const forbiddenHeaders = acah.has("*") ?
+  [] :
+  Object.keys(flag.requestHeaders).filter(header => {
+    const lcHeader = header.toLowerCase();
+    return !simpleHeaders.has(lcHeader) && !acah.has(lcHeader);
+  });
+  if (forbiddenHeaders.length > 0) {
+    properties.error = "Headers " + forbiddenHeaders + " forbidden";
+    dispatchError(xhr);
+    return false;
+  }
+  return true;
+}
+
+function requestErrorSteps(xhr, event, exception) {
+  const { flag, properties, upload } = xhr;
+
+  xhr.readyState = READY_STATES.DONE;
+  properties.send = false;
+
+  setResponseToNetworkError(xhr);
+
+  if (flag.synchronous) {
+    throw exception;
+  }
+
+  fireAnEvent("readystatechange", xhr);
+
+  if (!properties.uploadComplete) {
+    properties.uploadComplete = true;
+
+    if (properties.uploadListener) {
+      fireAnEvent(event, upload, ProgressEvent, { loaded: 0, total: 0, lengthComputable: false });
+      fireAnEvent("loadend", upload, ProgressEvent, { loaded: 0, total: 0, lengthComputable: false });
+    }
+  }
+
+  fireAnEvent(event, xhr, ProgressEvent, { loaded: 0, total: 0, lengthComputable: false });
+  fireAnEvent("loadend", xhr, ProgressEvent, { loaded: 0, total: 0, lengthComputable: false });
+}
+
+function setResponseToNetworkError(xhr) {
+  const { properties } = xhr;
+
+  properties.responseBuffer =
+    properties.responseCache =
+    properties.responseTextCache =
+    properties.responseXMLCache = null;
+
+  properties.responseHeaders = {};
+  xhr.status = 0;
+  xhr.statusText = "";
+}
+
+// return a "request" client object or an event emitter matching the same behaviour for unsupported protocols
+// the callback should be called with a "request" response object or an event emitter matching the same behaviour too
+function createClient(xhr) {
+  const { flag, properties } = xhr;
+  const urlObj = new URL(flag.uri);
+  const uri = urlObj.href;
+  const ucMethod = flag.method.toUpperCase();
+
+  const { requestManager } = flag;
+
+  if (urlObj.protocol === "file:") {
+    const response = new EventEmitter();
+    response.statusCode = 200;
+    response.rawHeaders = [];
+    response.headers = {};
+    const filePath = urlObj.pathname
+      .replace(/^file:\/\//, "")
+      .replace(/^\/([a-z]):\//i, "$1:/")
+      .replace(/%20/g, " ");
+
+    const client = new EventEmitter();
+
+    const readableStream = fs.createReadStream(filePath, { encoding: null });
+
+    readableStream.on("data", chunk => {
+      response.emit("data", chunk);
+      client.emit("data", chunk);
+    });
+
+    readableStream.on("end", () => {
+      response.emit("end");
+      client.emit("end");
+    });
+
+    readableStream.on("error", err => {
+      client.emit("error", err);
+    });
+
+    client.abort = function () {
+      readableStream.destroy();
+      client.emit("abort");
+    };
+
+    if (requestManager) {
+      const req = {
+        abort() {
+          properties.abortError = true;
+          xhr.abort();
+        }
+      };
+      requestManager.add(req);
+      const rmReq = requestManager.remove.bind(requestManager, req);
+      client.on("abort", rmReq);
+      client.on("error", rmReq);
+      client.on("end", rmReq);
+    }
+
+    process.nextTick(() => client.emit("response", response, urlObj.href));
+
+    return client;
+  }
+
+  if (urlObj.protocol === "data:") {
+    const response = new EventEmitter();
+
+    const client = new EventEmitter();
+
+    let buffer;
+    try {
+      const parsed = parseDataURL(uri);
+      const contentType = parsed.mimeType.toString();
+      buffer = parsed.body;
+      response.statusCode = 200;
+      response.rawHeaders = ["Content-Type", contentType];
+      response.headers = { "content-type": contentType };
+    } catch (err) {
+      process.nextTick(() => client.emit("error", err));
+      return client;
+    }
+
+    client.abort = () => {
+      // do nothing
+    };
+
+    process.nextTick(() => {
+      client.emit("response", response, urlObj.href);
+      process.nextTick(() => {
+        response.emit("data", buffer);
+        client.emit("data", buffer);
+        response.emit("end");
+        client.emit("end");
+      });
+    });
+
+    return client;
+  }
+  const agents = agentFactory(flag.proxy, flag.strictSSL);
+  const requestHeaders = {};
+
+  for (const header in flag.requestHeaders) {
+    requestHeaders[header] = flag.requestHeaders[header];
+  }
+
+  if (getRequestHeader(flag.requestHeaders, "referer") === null) {
+    requestHeaders.Referer = flag.referrer;
+  }
+  if (getRequestHeader(flag.requestHeaders, "user-agent") === null) {
+    requestHeaders["User-Agent"] = flag.userAgent;
+  }
+  if (getRequestHeader(flag.requestHeaders, "accept-language") === null) {
+    requestHeaders["Accept-Language"] = "en";
+  }
+  if (getRequestHeader(flag.requestHeaders, "accept") === null) {
+    requestHeaders.Accept = "*/*";
+  }
+
+  const crossOrigin = flag.origin !== urlObj.origin;
+  if (crossOrigin) {
+    requestHeaders.Origin = flag.origin;
+  }
+
+  const options = { rejectUnauthorized: flag.strictSSL, agents, followRedirects: true };
+  if (flag.auth) {
+    options.user = flag.auth.user || "";
+    options.pass = flag.auth.pass || "";
+  }
+  if (flag.cookieJar && (!crossOrigin || flag.withCredentials)) {
+    options.cookieJar = flag.cookieJar;
+  }
+
+  const { body } = flag;
+  const hasBody = body !== undefined &&
+                  body !== null &&
+                  body !== "" &&
+                  !(ucMethod === "HEAD" || ucMethod === "GET");
+
+  if (hasBody && getRequestHeader(flag.requestHeaders, "content-type") === null) {
+    requestHeaders["Content-Type"] = "text/plain;charset=UTF-8";
+  }
+
+  function doRequest() {
+    try {
+      let requestBody = body;
+      let len = 0;
+      if (hasBody) {
+        if (flag.formData) {
+          // TODO: implement https://html.spec.whatwg.org/#multipart-form-data
+          // directly instead of using an external library
+          requestBody = new FormData();
+          for (const entry of body) {
+            requestBody.append(entry.name, entry.value, entry.options);
+          }
+          len = requestBody.getLengthSync();
+          requestHeaders["Content-Type"] = `multipart/form-data; boundary=${requestBody.getBoundary()}`;
+        } else {
+          if (typeof body === "string") {
+            len = Buffer.byteLength(body);
+          } else {
+            len = body.length;
+          }
+          requestBody = Buffer.isBuffer(requestBody) ? requestBody : Buffer.from(requestBody);
+        }
+        requestHeaders["Content-Length"] = len;
+      }
+      requestHeaders["Accept-Encoding"] = "gzip, deflate";
+      const requestClient = new Request(uri, options, { method: flag.method, headers: requestHeaders });
+      if (hasBody) {
+        if (flag.formData) {
+          requestBody.on("error", err => {
+            requestClient.emit("error", err);
+            requestClient.abort();
+          });
+          requestClient.pipeRequest(requestBody);
+        } else {
+          requestClient.write(requestBody);
+        }
+      }
+      return requestClient;
+    } catch (e) {
+      const eventEmitterclient = new EventEmitter();
+      process.nextTick(() => eventEmitterclient.emit("error", e));
+      eventEmitterclient.end = () => {};
+      return eventEmitterclient;
+    }
+  }
+
+  let client;
+
+  const nonSimpleHeaders = Object.keys(flag.requestHeaders)
+    .filter(header => !simpleHeaders.has(header.toLowerCase()));
+
+  if (crossOrigin && (!simpleMethods.has(ucMethod) || nonSimpleHeaders.length > 0 || properties.uploadListener)) {
+    client = new EventEmitter();
+
+    const preflightRequestHeaders = {};
+    for (const header in requestHeaders) {
+      // the only existing request headers the cors spec allows on the preflight request are Origin and Referer
+      const lcHeader = header.toLowerCase();
+      if (lcHeader === "origin" || lcHeader === "referer") {
+        preflightRequestHeaders[header] = requestHeaders[header];
+      }
+    }
+
+    preflightRequestHeaders["Access-Control-Request-Method"] = flag.method;
+    if (nonSimpleHeaders.length > 0) {
+      preflightRequestHeaders["Access-Control-Request-Headers"] = nonSimpleHeaders.join(", ");
+    }
+
+    preflightRequestHeaders["User-Agent"] = flag.userAgent;
+
+    flag.preflight = true;
+
+    const rejectUnauthorized = flag.strictSSL;
+    const preflightClient = new Request(
+      uri,
+      { agents, followRedirects: false },
+      { method: "OPTIONS", headers: preflightRequestHeaders, rejectUnauthorized }
+    );
+
+    preflightClient.on("response", resp => {
+      // don't send the real request if the preflight request returned an error
+      if (resp.statusCode < 200 || resp.statusCode > 299) {
+        client.emit("error", new Error("Response for preflight has invalid HTTP status code " + resp.statusCode));
+        return;
+      }
+      // don't send the real request if we aren't allowed to use the headers
+      if (!validCORSPreflightHeaders(xhr, resp, flag, properties)) {
+        setResponseToNetworkError(xhr);
+        return;
+      }
+      // Set request gzip option right before headers are set
+      const realClient = doRequest();
+      realClient.on("response", (...args) => client.emit("response", ...args));
+      realClient.on("data", chunk => client.emit("data", chunk));
+      realClient.on("end", () => client.emit("end"));
+      realClient.on("abort", () => client.emit("abort"));
+      realClient.on("request", req => {
+        client.headers = realClient.headers;
+        client.emit("request", req);
+      });
+      realClient.on("redirect", (...args) => {
+        client.emit("redirect", ...args);
+      });
+      realClient.on("error", err => {
+        client.emit("error", err);
+      });
+      client.abort = () => {
+        realClient.abort();
+      };
+      setImmediate(() => realClient.end());
+    });
+
+    preflightClient.on("error", err => {
+      client.emit("error", err);
+    });
+
+    client.abort = () => {
+      preflightClient.abort();
+    };
+    setImmediate(() => preflightClient.end());
+  } else {
+    client = doRequest();
+    setImmediate(() => client.end());
+  }
+
+  if (requestManager) {
+    const req = {
+      abort() {
+        properties.abortError = true;
+        xhr.abort();
+      }
+    };
+    requestManager.add(req);
+    const rmReq = requestManager.remove.bind(requestManager, req);
+    client.on("abort", rmReq);
+    client.on("error", rmReq);
+    client.on("end", rmReq);
+  }
+  return client;
+}
+
+exports.headerListSeparatorRegexp = headerListSeparatorRegexp;
+exports.simpleHeaders = simpleHeaders;
+exports.preflightHeaders = preflightHeaders;
+exports.getRequestHeader = getRequestHeader;
+exports.updateRequestHeader = updateRequestHeader;
+exports.dispatchError = dispatchError;
+exports.validCORSHeaders = validCORSHeaders;
+exports.requestErrorSteps = requestErrorSteps;
+exports.setResponseToNetworkError = setResponseToNetworkError;
+exports.createClient = createClient;
Index: frontend/node_modules/jsdom/lib/jsdom/named-properties-tracker.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/named-properties-tracker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/named-properties-tracker.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,158 @@
+"use strict";
+// https://heycam.github.io/webidl/#idl-named-properties
+
+const IS_NAMED_PROPERTY = Symbol("is named property");
+const TRACKER = Symbol("named property tracker");
+
+/**
+ * Create a new NamedPropertiesTracker for the given `object`.
+ *
+ * Named properties are used in DOM to let you lookup (for example) a Node by accessing a property on another object.
+ * For example `window.foo` might resolve to an image element with id "foo".
+ *
+ * This tracker is a workaround because the ES6 Proxy feature is not yet available.
+ *
+ * @param {Object} object Object used to write properties to
+ * @param {Object} objectProxy Object used to check if a property is already defined
+ * @param {Function} resolverFunc Each time a property is accessed, this function is called to determine the value of
+ *        the property. The function is passed 3 arguments: (object, name, values).
+ *        `object` is identical to the `object` parameter of this `create` function.
+ *        `name` is the name of the property.
+ *        `values` is a function that returns a Set with all the tracked values for this name. The order of these
+ *        values is undefined.
+ *
+ * @returns {NamedPropertiesTracker}
+ */
+exports.create = function (object, objectProxy, resolverFunc) {
+  if (object[TRACKER]) {
+    throw Error("A NamedPropertiesTracker has already been created for this object");
+  }
+
+  const tracker = new NamedPropertiesTracker(object, objectProxy, resolverFunc);
+  object[TRACKER] = tracker;
+  return tracker;
+};
+
+exports.get = function (object) {
+  if (!object) {
+    return null;
+  }
+
+  return object[TRACKER] || null;
+};
+
+function NamedPropertiesTracker(object, objectProxy, resolverFunc) {
+  this.object = object;
+  this.objectProxy = objectProxy;
+  this.resolverFunc = resolverFunc;
+  this.trackedValues = new Map(); // Map<Set<value>>
+}
+
+function newPropertyDescriptor(tracker, name) {
+  const emptySet = new Set();
+
+  function getValues() {
+    return tracker.trackedValues.get(name) || emptySet;
+  }
+
+  const descriptor = {
+    enumerable: true,
+    configurable: true,
+    get() {
+      return tracker.resolverFunc(tracker.object, name, getValues);
+    },
+    set(value) {
+      Object.defineProperty(tracker.object, name, {
+        enumerable: true,
+        configurable: true,
+        writable: true,
+        value
+      });
+    }
+  };
+
+  descriptor.get[IS_NAMED_PROPERTY] = true;
+  descriptor.set[IS_NAMED_PROPERTY] = true;
+  return descriptor;
+}
+
+/**
+ * Track a value (e.g. a Node) for a specified name.
+ *
+ * Values can be tracked eagerly, which means that not all tracked values *have* to appear in the output. The resolver
+ * function that was passed to the output may filter the value.
+ *
+ * Tracking the same `name` and `value` pair multiple times has no effect
+ *
+ * @param {String} name
+ * @param {*} value
+ */
+NamedPropertiesTracker.prototype.track = function (name, value) {
+  if (name === undefined || name === null || name === "") {
+    return;
+  }
+
+  let valueSet = this.trackedValues.get(name);
+  if (!valueSet) {
+    valueSet = new Set();
+    this.trackedValues.set(name, valueSet);
+  }
+
+  valueSet.add(value);
+
+  if (name in this.objectProxy) {
+    // already added our getter or it is not a named property (e.g. "addEventListener")
+    return;
+  }
+
+  const descriptor = newPropertyDescriptor(this, name);
+  Object.defineProperty(this.object, name, descriptor);
+};
+
+/**
+ * Stop tracking a previously tracked `name` & `value` pair, see track().
+ *
+ * Untracking the same `name` and `value` pair multiple times has no effect
+ *
+ * @param {String} name
+ * @param {*} value
+ */
+NamedPropertiesTracker.prototype.untrack = function (name, value) {
+  if (name === undefined || name === null || name === "") {
+    return;
+  }
+
+  const valueSet = this.trackedValues.get(name);
+  if (!valueSet) {
+    // the value is not present
+    return;
+  }
+
+  if (!valueSet.delete(value)) {
+    // the value was not present
+    return;
+  }
+
+  if (valueSet.size === 0) {
+    this.trackedValues.delete(name);
+  }
+
+  if (valueSet.size > 0) {
+    // other values for this name are still present
+    return;
+  }
+
+  // at this point there are no more values, delete the property
+
+  const descriptor = Object.getOwnPropertyDescriptor(this.object, name);
+
+  if (!descriptor || !descriptor.get || descriptor.get[IS_NAMED_PROPERTY] !== true) {
+    // Not defined by NamedPropertyTracker
+    return;
+  }
+
+  // note: delete puts the object in dictionary mode.
+  // if this turns out to be a performance issue, maybe add:
+  // https://github.com/petkaantonov/bluebird/blob/3e36fc861ac5795193ba37935333eb6ef3716390/src/util.js#L177
+  delete this.object[name];
+};
Index: frontend/node_modules/jsdom/lib/jsdom/utils.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/utils.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,165 @@
+"use strict";
+const path = require("path");
+const whatwgURL = require("whatwg-url");
+const { domSymbolTree } = require("./living/helpers/internal-constants");
+const SYMBOL_TREE_POSITION = require("symbol-tree").TreePosition;
+
+exports.hasWeakRefs = typeof WeakRef === "function";
+
+exports.toFileUrl = function (fileName) {
+  // Beyond just the `path.resolve`, this is mostly for the benefit of Windows,
+  // where we need to convert "\" to "/" and add an extra "/" prefix before the
+  // drive letter.
+  let pathname = path.resolve(process.cwd(), fileName).replace(/\\/g, "/");
+  if (pathname[0] !== "/") {
+    pathname = "/" + pathname;
+  }
+
+  // path might contain spaces, so convert those to %20
+  return "file://" + encodeURI(pathname);
+};
+
+/**
+ * Define a set of properties on an object, by copying the property descriptors
+ * from the original object.
+ *
+ * - `object` {Object} the target object
+ * - `properties` {Object} the source from which to copy property descriptors
+ */
+exports.define = function define(object, properties) {
+  for (const name of Object.getOwnPropertyNames(properties)) {
+    const propDesc = Object.getOwnPropertyDescriptor(properties, name);
+    Object.defineProperty(object, name, propDesc);
+  }
+};
+
+/**
+ * Define a list of constants on a constructor and its .prototype
+ *
+ * - `Constructor` {Function} the constructor to define the constants on
+ * - `propertyMap` {Object}  key/value map of properties to define
+ */
+exports.addConstants = function addConstants(Constructor, propertyMap) {
+  for (const property in propertyMap) {
+    const value = propertyMap[property];
+    addConstant(Constructor, property, value);
+    addConstant(Constructor.prototype, property, value);
+  }
+};
+
+function addConstant(object, property, value) {
+  Object.defineProperty(object, property, {
+    configurable: false,
+    enumerable: true,
+    writable: false,
+    value
+  });
+}
+
+exports.mixin = (target, source) => {
+  const keys = Reflect.ownKeys(source);
+  for (let i = 0; i < keys.length; ++i) {
+    if (keys[i] in target) {
+      continue;
+    }
+
+    Object.defineProperty(target, keys[i], Object.getOwnPropertyDescriptor(source, keys[i]));
+  }
+};
+
+let memoizeQueryTypeCounter = 0;
+
+/**
+ * Returns a version of a method that memoizes specific types of calls on the object
+ *
+ * - `fn` {Function} the method to be memozied
+ */
+exports.memoizeQuery = function memoizeQuery(fn) {
+  // Only memoize query functions with arity <= 2
+  if (fn.length > 2) {
+    return fn;
+  }
+
+  const type = memoizeQueryTypeCounter++;
+
+  return function (...args) {
+    if (!this._memoizedQueries) {
+      return fn.apply(this, args);
+    }
+
+    if (!this._memoizedQueries[type]) {
+      this._memoizedQueries[type] = Object.create(null);
+    }
+
+    let key;
+    if (args.length === 1 && typeof args[0] === "string") {
+      key = args[0];
+    } else if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "string") {
+      key = args[0] + "::" + args[1];
+    } else {
+      return fn.apply(this, args);
+    }
+
+    if (!(key in this._memoizedQueries[type])) {
+      this._memoizedQueries[type][key] = fn.apply(this, args);
+    }
+    return this._memoizedQueries[type][key];
+  };
+};
+
+function isValidAbsoluteURL(str) {
+  return whatwgURL.parseURL(str) !== null;
+}
+
+exports.isValidTargetOrigin = function (str) {
+  return str === "*" || str === "/" || isValidAbsoluteURL(str);
+};
+
+exports.simultaneousIterators = function* (first, second) {
+  for (;;) {
+    const firstResult = first.next();
+    const secondResult = second.next();
+
+    if (firstResult.done && secondResult.done) {
+      return;
+    }
+
+    yield [
+      firstResult.done ? null : firstResult.value,
+      secondResult.done ? null : secondResult.value
+    ];
+  }
+};
+
+exports.treeOrderSorter = function (a, b) {
+  const compare = domSymbolTree.compareTreePosition(a, b);
+
+  if (compare & SYMBOL_TREE_POSITION.PRECEDING) { // b is preceding a
+    return 1;
+  }
+
+  if (compare & SYMBOL_TREE_POSITION.FOLLOWING) {
+    return -1;
+  }
+
+  // disconnected or equal:
+  return 0;
+};
+
+/* eslint-disable global-require */
+
+exports.Canvas = null;
+let canvasInstalled = false;
+try {
+  require.resolve("canvas");
+  canvasInstalled = true;
+} catch (e) {
+  // canvas is not installed
+}
+if (canvasInstalled) {
+  const Canvas = require("canvas");
+  if (typeof Canvas.createCanvas === "function") {
+    // In browserify, the require will succeed but return an empty object
+    exports.Canvas = Canvas;
+  }
+}
Index: frontend/node_modules/jsdom/lib/jsdom/virtual-console.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/virtual-console.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/virtual-console.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,34 @@
+"use strict";
+const { EventEmitter } = require("events");
+
+module.exports = class VirtualConsole extends EventEmitter {
+  constructor() {
+    super();
+
+    this.on("error", () => {
+      // If "error" event has no listeners,
+      // EventEmitter throws an exception
+    });
+  }
+
+  sendTo(anyConsole, options) {
+    if (options === undefined) {
+      options = {};
+    }
+
+    for (const method of Object.keys(anyConsole)) {
+      if (typeof anyConsole[method] === "function") {
+        function onMethodCall(...args) {
+          anyConsole[method](...args);
+        }
+        this.on(method, onMethodCall);
+      }
+    }
+
+    if (!options.omitJSDOMErrors) {
+      this.on("jsdomError", e => anyConsole.error(e.stack, e.detail));
+    }
+
+    return this;
+  }
+};
Index: frontend/node_modules/jsdom/lib/jsdom/vm-shim.js
===================================================================
--- frontend/node_modules/jsdom/lib/jsdom/vm-shim.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/jsdom/lib/jsdom/vm-shim.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,106 @@
+"use strict";
+/* eslint-disable no-new-func */
+const acorn = require("acorn");
+const findGlobals = require("acorn-globals");
+const escodegen = require("escodegen");
+const jsGlobals = require("./browser/js-globals.json");
+
+// We can't use the default browserify vm shim because it doesn't work in a web worker.
+
+// "eval" is skipped because it's set to a function that calls `runInContext`:
+const jsGlobalEntriesToInstall = Object.entries(jsGlobals).filter(([name]) => name !== "eval" && name in global);
+
+exports.createContext = function (sandbox) {
+  // TODO: This should probably use a symbol
+  Object.defineProperty(sandbox, "__isVMShimContext", {
+    value: true,
+    writable: true,
+    configurable: true,
+    enumerable: false
+  });
+
+  for (const [globalName, globalPropDesc] of jsGlobalEntriesToInstall) {
+    const propDesc = { ...globalPropDesc, value: global[globalName] };
+    Object.defineProperty(sandbox, globalName, propDesc);
+  }
+
+  Object.defineProperty(sandbox, "eval", {
+    value(code) {
+      return exports.runInContext(code, sandbox);
+    },
+    writable: true,
+    configurable: true,
+    enumerable: false
+  });
+};
+
+exports.isContext = function (sandbox) {
+  return sandbox.__isVMShimContext;
+};
+
+exports.runInContext = function (code, contextifiedSandbox, options) {
+  if (code === "this") {
+    // Special case for during window creation.
+    return contextifiedSandbox;
+  }
+
+  if (options === undefined) {
+    options = {};
+  }
+
+  const comments = [];
+  const tokens = [];
+  const ast = acorn.parse(code, {
+    allowReturnOutsideFunction: true,
+    ranges: true,
+    // collect comments in Esprima's format
+    onComment: comments,
+    // collect token ranges
+    onToken: tokens
+  });
+
+  // make sure we keep comments
+  escodegen.attachComments(ast, comments, tokens);
+
+  const globals = findGlobals(ast);
+  for (let i = 0; i < globals.length; ++i) {
+    if (globals[i].name === "window" || globals[i].name === "this") {
+      continue;
+    }
+
+    const { nodes } = globals[i];
+    for (let j = 0; j < nodes.length; ++j) {
+      const { type, name } = nodes[j];
+      nodes[j].type = "MemberExpression";
+      nodes[j].property = { name, type };
+      nodes[j].computed = false;
+      nodes[j].object = {
+        name: "window",
+        type: "Identifier"
+      };
+    }
+  }
+
+  const lastNode = ast.body[ast.body.length - 1];
+  if (lastNode.type === "ExpressionStatement") {
+    lastNode.type = "ReturnStatement";
+    lastNode.argument = lastNode.expression;
+    delete lastNode.expression;
+  }
+
+  const rewrittenCode = escodegen.generate(ast, { comment: true });
+  const suffix = options.filename !== undefined ? "\n//# sourceURL=" + options.filename : "";
+
+  return Function("window", rewrittenCode + suffix).bind(contextifiedSandbox)(contextifiedSandbox);
+};
+
+exports.Script = class VMShimScript {
+  constructor(code, options) {
+    this._code = code;
+    this._options = options;
+  }
+
+  runInContext(sandbox, options) {
+    return exports.runInContext(this._code, sandbox, { ...this._options, ...options });
+  }
+};
