summaryrefslogtreecommitdiff
path: root/alarm/node_modules/jsdom/lib/jsdom/browser
diff options
context:
space:
mode:
Diffstat (limited to 'alarm/node_modules/jsdom/lib/jsdom/browser')
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/Window.js933
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js789
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/js-globals.json307
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/not-implemented.js13
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/parser/html.js223
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/parser/index.js37
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/parser/xml.js202
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js114
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js8
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js95
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js33
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js142
-rw-r--r--alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js142
13 files changed, 3038 insertions, 0 deletions
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/Window.js b/alarm/node_modules/jsdom/lib/jsdom/browser/Window.js
new file mode 100644
index 0000000..9b2d75f
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/Window.js
@@ -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);
+}
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js b/alarm/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js
new file mode 100644
index 0000000..78f69bb
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/default-stylesheet.js
@@ -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. */
+
+`;
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/js-globals.json b/alarm/node_modules/jsdom/lib/jsdom/browser/js-globals.json
new file mode 100644
index 0000000..c4de05f
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/js-globals.json
@@ -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
+ }
+}
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/not-implemented.js b/alarm/node_modules/jsdom/lib/jsdom/browser/not-implemented.js
new file mode 100644
index 0000000..a87cc95
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/not-implemented.js
@@ -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);
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/parser/html.js b/alarm/node_modules/jsdom/lib/jsdom/browser/parser/html.js
new file mode 100644
index 0000000..198cc2c
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/parser/html.js
@@ -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
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/parser/index.js b/alarm/node_modules/jsdom/lib/jsdom/browser/parser/index.js
new file mode 100644
index 0000000..e09df95
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/parser/index.js
@@ -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
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/parser/xml.js b/alarm/node_modules/jsdom/lib/jsdom/browser/parser/xml.js
new file mode 100644
index 0000000..f5f13c3
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/parser/xml.js
@@ -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
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js
new file mode 100644
index 0000000..51c7bb7
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/async-resource-queue.js
@@ -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);
+ }
+ }
+ }
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js
new file mode 100644
index 0000000..985509c
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/no-op-resource-loader.js
@@ -0,0 +1,8 @@
+"use strict";
+const ResourceLoader = require("./resource-loader.js");
+
+module.exports = class NoOpResourceLoader extends ResourceLoader {
+ fetch() {
+ return null;
+ }
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js
new file mode 100644
index 0000000..8a10613
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/per-document-resource-loader.js
@@ -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 });
+ });
+ }
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js
new file mode 100644
index 0000000..dbf6ccb
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/request-manager.js
@@ -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;
+ }
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js
new file mode 100644
index 0000000..2af8d63
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-loader.js
@@ -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}`));
+ }
+ }
+ }
+};
diff --git a/alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js
new file mode 100644
index 0000000..c7d8f0f
--- /dev/null
+++ b/alarm/node_modules/jsdom/lib/jsdom/browser/resources/resource-queue.js
@@ -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();
+ }
+ }
+};