{ "version": 3, "sources": ["../../../node_modules/@rails/actioncable/src/adapters.js", "../../../node_modules/@rails/actioncable/src/logger.js", "../../../node_modules/@rails/actioncable/src/connection_monitor.js", "../../../node_modules/@rails/actioncable/src/internal.js", "../../../node_modules/@rails/actioncable/src/connection.js", "../../../node_modules/@rails/actioncable/src/subscription.js", "../../../node_modules/@rails/actioncable/src/subscription_guarantor.js", "../../../node_modules/@rails/actioncable/src/subscriptions.js", "../../../node_modules/@rails/actioncable/src/consumer.js", "../../../node_modules/@rails/actioncable/src/index.js", "../../../node_modules/dompurify/src/utils.js", "../../../node_modules/dompurify/src/tags.js", "../../../node_modules/dompurify/src/attrs.js", "../../../node_modules/dompurify/src/regexp.js", "../../../node_modules/dompurify/src/purify.js", "../../../node_modules/qrious/node_modules/nevis/src/extend.js", "../../../node_modules/qrious/node_modules/nevis/src/nevis.js", "../../../node_modules/qrious/node_modules/nevis/lite.js", "../../../node_modules/qrious/node_modules/qrious-core/src/renderer/Renderer.js", "../../../node_modules/qrious/node_modules/qrious-core/src/renderer/CanvasRenderer.js", "../../../node_modules/qrious/node_modules/qrious-core/src/Alignment.js", "../../../node_modules/qrious/node_modules/qrious-core/src/ErrorCorrection.js", "../../../node_modules/qrious/node_modules/qrious-core/src/Galois.js", "../../../node_modules/qrious/node_modules/qrious-core/src/Version.js", "../../../node_modules/qrious/node_modules/qrious-core/src/Frame.js", "../../../node_modules/qrious/node_modules/qrious-core/src/renderer/ImageRenderer.js", "../../../node_modules/qrious/node_modules/qrious-core/src/option/Option.js", "../../../node_modules/qrious/node_modules/qrious-core/src/util/Utilities.js", "../../../node_modules/qrious/node_modules/qrious-core/src/option/OptionManager.js", "../../../node_modules/qrious/node_modules/qrious-core/src/service/ServiceManager.js", "../../../node_modules/qrious/node_modules/qrious-core/src/QRious.js", "../../../node_modules/qrious/node_modules/qrious-core/index.js", "../../../node_modules/qrious/node_modules/qrious-core/src/service/Service.js", "../../../node_modules/qrious/node_modules/qrious-core/src/service/element/ElementService.js", "../../../node_modules/qrious/src/service/element/BrowserElementService.js", "../../../node_modules/qrious/src/QRious.js", "../../../node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/snakeize.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable_stream_source_element.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/fetch_requests.js", "../../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/index.js", "../../javascript/initializers/polyfill_Array_flat.js", "../../javascript/initializers/turbo_drive_render_hack.js", "../../javascript/initializers/turbo_drive_scroll_hack.js", "../../javascript/lib/helpers.js", "../../javascript/lib/beacon.js", "../../javascript/initializers/beacon.js", "../../../node_modules/@hotwired/stimulus/dist/stimulus.js", "../../javascript/controllers/application.js", "../../javascript/lib/reactor.js", "../../javascript/controllers/application/form_controller.js", "../../javascript/controllers/application/instructions_controller.js", "../../javascript/controllers/async_download_controller.js", "../../../node_modules/@kurkle/color/dist/color.esm.js", "../../../node_modules/chart.js/src/helpers/helpers.core.ts", "../../../node_modules/chart.js/src/helpers/helpers.math.ts", "../../../node_modules/chart.js/src/helpers/helpers.collection.ts", "../../../node_modules/chart.js/src/helpers/helpers.extras.ts", "../../../node_modules/chart.js/src/helpers/helpers.easing.ts", "../../../node_modules/chart.js/src/helpers/helpers.color.ts", "../../../node_modules/chart.js/src/core/core.animations.defaults.js", "../../../node_modules/chart.js/src/core/core.layouts.defaults.js", "../../../node_modules/chart.js/src/helpers/helpers.intl.ts", "../../../node_modules/chart.js/src/core/core.ticks.js", "../../../node_modules/chart.js/src/core/core.scale.defaults.js", "../../../node_modules/chart.js/src/core/core.defaults.js", "../../../node_modules/chart.js/src/helpers/helpers.canvas.ts", "../../../node_modules/chart.js/src/helpers/helpers.options.ts", "../../../node_modules/chart.js/src/helpers/helpers.config.ts", "../../../node_modules/chart.js/src/helpers/helpers.curve.ts", "../../../node_modules/chart.js/src/helpers/helpers.dom.ts", "../../../node_modules/chart.js/src/helpers/helpers.interpolation.ts", "../../../node_modules/chart.js/src/helpers/helpers.rtl.ts", "../../../node_modules/chart.js/src/helpers/helpers.segment.js", "../../../node_modules/chart.js/src/core/core.animator.js", "../../../node_modules/chart.js/src/core/core.animation.js", "../../../node_modules/chart.js/src/core/core.animations.js", "../../../node_modules/chart.js/src/core/core.datasetController.js", "../../../node_modules/chart.js/src/controllers/controller.bar.js", "../../../node_modules/chart.js/src/controllers/controller.bubble.js", "../../../node_modules/chart.js/src/controllers/controller.doughnut.js", "../../../node_modules/chart.js/src/controllers/controller.line.js", "../../../node_modules/chart.js/src/controllers/controller.polarArea.js", "../../../node_modules/chart.js/src/controllers/controller.pie.js", "../../../node_modules/chart.js/src/controllers/controller.radar.js", "../../../node_modules/chart.js/src/controllers/controller.scatter.js", "../../../node_modules/chart.js/src/core/core.adapters.ts", "../../../node_modules/chart.js/src/core/core.interaction.js", "../../../node_modules/chart.js/src/core/core.layouts.js", "../../../node_modules/chart.js/src/platform/platform.base.js", "../../../node_modules/chart.js/src/platform/platform.basic.js", "../../../node_modules/chart.js/src/platform/platform.dom.js", "../../../node_modules/chart.js/src/platform/index.js", "../../../node_modules/chart.js/src/core/core.element.ts", "../../../node_modules/chart.js/src/core/core.scale.autoskip.js", "../../../node_modules/chart.js/src/core/core.scale.js", "../../../node_modules/chart.js/src/core/core.typedRegistry.js", "../../../node_modules/chart.js/src/core/core.registry.js", "../../../node_modules/chart.js/src/core/core.plugins.js", "../../../node_modules/chart.js/src/core/core.config.js", "../../../node_modules/chart.js/src/core/core.controller.js", "../../../node_modules/chart.js/src/elements/element.arc.ts", "../../../node_modules/chart.js/src/elements/element.line.js", "../../../node_modules/chart.js/src/elements/element.point.ts", "../../../node_modules/chart.js/src/elements/element.bar.js", "../../../node_modules/chart.js/src/plugins/plugin.colors.ts", "../../../node_modules/chart.js/src/plugins/plugin.decimation.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/filler.segment.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/filler.helper.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/filler.options.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/filler.target.stack.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/simpleArc.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/filler.target.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/filler.drawing.js", "../../../node_modules/chart.js/src/plugins/plugin.filler/index.js", "../../../node_modules/chart.js/src/plugins/plugin.legend.js", "../../../node_modules/chart.js/src/plugins/plugin.title.js", "../../../node_modules/chart.js/src/plugins/plugin.subtitle.js", "../../../node_modules/chart.js/src/plugins/plugin.tooltip.js", "../../../node_modules/chart.js/src/scales/scale.category.js", "../../../node_modules/chart.js/src/scales/scale.linearbase.js", "../../../node_modules/chart.js/src/scales/scale.linear.js", "../../../node_modules/chart.js/src/scales/scale.logarithmic.js", "../../../node_modules/chart.js/src/scales/scale.radialLinear.js", "../../../node_modules/chart.js/src/scales/scale.time.js", "../../../node_modules/chart.js/src/scales/scale.timeseries.js", "../../../node_modules/chart.js/src/index.ts", "../../../node_modules/chart.js/auto/auto.js", "../../javascript/controllers/chart_states_controller.js", "../../javascript/controllers/embed_spinner_controller.js", "../../javascript/controllers/flash_component_controller.js", "../../../node_modules/flatpickr/dist/esm/types/options.js", "../../../node_modules/flatpickr/dist/esm/l10n/default.js", "../../../node_modules/flatpickr/dist/esm/utils/index.js", "../../../node_modules/flatpickr/dist/esm/utils/dom.js", "../../../node_modules/flatpickr/dist/esm/utils/formatting.js", "../../../node_modules/flatpickr/dist/esm/utils/dates.js", "../../../node_modules/flatpickr/dist/esm/utils/polyfills.js", "../../../node_modules/flatpickr/dist/esm/index.js", "../../javascript/controllers/flatpickr_controller.js", "../../javascript/controllers/form/autofocus_controller.js", "../../javascript/controllers/form/breakout_controller.js", "../../javascript/controllers/form/flash_component_controller.js", "../../../node_modules/uuid/dist/esm-browser/stringify.js", "../../../node_modules/uuid/dist/esm-browser/rng.js", "../../../node_modules/uuid/dist/esm-browser/native.js", "../../../node_modules/uuid/dist/esm-browser/v4.js", "../../javascript/controllers/form/id_controller.js", "../../javascript/controllers/form/modal_component_closer_controller.js", "../../javascript/controllers/form/range_number_controller.js", "../../javascript/controllers/form/reload_on_change_controller.js", "../../javascript/controllers/form/spinner_controller.js", "../../javascript/controllers/form/turnstile_controller.js", "../../javascript/controllers/form/url_controller.js", "../../javascript/controllers/manager/form_controller.js", "../../javascript/controllers/manager_switch_component_controller.js", "../../javascript/controllers/modal_component_controller.js", "../../javascript/controllers/open_modal_component_controller.js", "../../javascript/controllers/qrcode_controller.js", "../../javascript/controllers/remove_controller.js", "../../javascript/controllers/show_controller.js", "../../javascript/controllers/spinner_controller.js", "../../javascript/controllers/submit_controller.js", "../../../node_modules/@stripe/stripe-js/dist/index.mjs", "../../javascript/controllers/subscription/form_controller.js", "../../javascript/controllers/tabs_controller.js", "../../javascript/controllers/time_range/form_controller.js", "../../../node_modules/sortablejs/modular/sortable.esm.js", "../../javascript/controllers/time_range/sortable_controller.js", "../../../node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs", "../../../node_modules/@floating-ui/core/dist/floating-ui.core.mjs", "../../../node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs", "../../../node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs", "../../javascript/controllers/tooltip_controller.js", "../../javascript/controllers/turbo_frame_reloader_controller.js", "../../javascript/controllers/index.js"], "sourcesContent": ["export default {\n logger: typeof console !== \"undefined\" ? console : undefined,\n WebSocket: typeof WebSocket !== \"undefined\" ? WebSocket : undefined,\n}\n", "import adapters from \"./adapters\"\n\n// The logger is disabled by default. You can enable it with:\n//\n// ActionCable.logger.enabled = true\n//\n// Example:\n//\n// import * as ActionCable from '@rails/actioncable'\n//\n// ActionCable.logger.enabled = true\n// ActionCable.logger.log('Connection Established.')\n//\n\nexport default {\n log(...messages) {\n if (this.enabled) {\n messages.push(Date.now())\n adapters.logger.log(\"[ActionCable]\", ...messages)\n }\n },\n}\n", "import logger from \"./logger\"\n\n// Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting\n// revival reconnections if things go astray. Internal class, not intended for direct user manipulation.\n\nconst now = () => new Date().getTime()\n\nconst secondsSince = time => (now() - time) / 1000\n\nclass ConnectionMonitor {\n constructor(connection) {\n this.visibilityDidChange = this.visibilityDidChange.bind(this)\n this.connection = connection\n this.reconnectAttempts = 0\n }\n\n start() {\n if (!this.isRunning()) {\n this.startedAt = now()\n delete this.stoppedAt\n this.startPolling()\n addEventListener(\"visibilitychange\", this.visibilityDidChange)\n logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`)\n }\n }\n\n stop() {\n if (this.isRunning()) {\n this.stoppedAt = now()\n this.stopPolling()\n removeEventListener(\"visibilitychange\", this.visibilityDidChange)\n logger.log(\"ConnectionMonitor stopped\")\n }\n }\n\n isRunning() {\n return this.startedAt && !this.stoppedAt\n }\n\n recordMessage() {\n this.pingedAt = now()\n }\n\n recordConnect() {\n this.reconnectAttempts = 0\n delete this.disconnectedAt\n logger.log(\"ConnectionMonitor recorded connect\")\n }\n\n recordDisconnect() {\n this.disconnectedAt = now()\n logger.log(\"ConnectionMonitor recorded disconnect\")\n }\n\n // Private\n\n startPolling() {\n this.stopPolling()\n this.poll()\n }\n\n stopPolling() {\n clearTimeout(this.pollTimeout)\n }\n\n poll() {\n this.pollTimeout = setTimeout(() => {\n this.reconnectIfStale()\n this.poll()\n }\n , this.getPollInterval())\n }\n\n getPollInterval() {\n const { staleThreshold, reconnectionBackoffRate } = this.constructor\n const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10))\n const jitterMax = this.reconnectAttempts === 0 ? 1.0 : reconnectionBackoffRate\n const jitter = jitterMax * Math.random()\n return staleThreshold * 1000 * backoff * (1 + jitter)\n }\n\n reconnectIfStale() {\n if (this.connectionIsStale()) {\n logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`)\n this.reconnectAttempts++\n if (this.disconnectedRecently()) {\n logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`)\n } else {\n logger.log(\"ConnectionMonitor reopening\")\n this.connection.reopen()\n }\n }\n }\n\n get refreshedAt() {\n return this.pingedAt ? this.pingedAt : this.startedAt\n }\n\n connectionIsStale() {\n return secondsSince(this.refreshedAt) > this.constructor.staleThreshold\n }\n\n disconnectedRecently() {\n return this.disconnectedAt && (secondsSince(this.disconnectedAt) < this.constructor.staleThreshold)\n }\n\n visibilityDidChange() {\n if (document.visibilityState === \"visible\") {\n setTimeout(() => {\n if (this.connectionIsStale() || !this.connection.isOpen()) {\n logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`)\n this.connection.reopen()\n }\n }\n , 200)\n }\n }\n\n}\n\nConnectionMonitor.staleThreshold = 6 // Server::Connections::BEAT_INTERVAL * 2 (missed two pings)\nConnectionMonitor.reconnectionBackoffRate = 0.15\n\nexport default ConnectionMonitor\n", "export default {\n \"message_types\": {\n \"welcome\": \"welcome\",\n \"disconnect\": \"disconnect\",\n \"ping\": \"ping\",\n \"confirmation\": \"confirm_subscription\",\n \"rejection\": \"reject_subscription\"\n },\n \"disconnect_reasons\": {\n \"unauthorized\": \"unauthorized\",\n \"invalid_request\": \"invalid_request\",\n \"server_restart\": \"server_restart\",\n \"remote\": \"remote\"\n },\n \"default_mount_path\": \"/cable\",\n \"protocols\": [\n \"actioncable-v1-json\",\n \"actioncable-unsupported\"\n ]\n}\n", "import adapters from \"./adapters\"\nimport ConnectionMonitor from \"./connection_monitor\"\nimport INTERNAL from \"./internal\"\nimport logger from \"./logger\"\n\n// Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.\n\nconst {message_types, protocols} = INTERNAL\nconst supportedProtocols = protocols.slice(0, protocols.length - 1)\n\nconst indexOf = [].indexOf\n\nclass Connection {\n constructor(consumer) {\n this.open = this.open.bind(this)\n this.consumer = consumer\n this.subscriptions = this.consumer.subscriptions\n this.monitor = new ConnectionMonitor(this)\n this.disconnected = true\n }\n\n send(data) {\n if (this.isOpen()) {\n this.webSocket.send(JSON.stringify(data))\n return true\n } else {\n return false\n }\n }\n\n open() {\n if (this.isActive()) {\n logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`)\n return false\n } else {\n const socketProtocols = [...protocols, ...this.consumer.subprotocols || []]\n logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`)\n if (this.webSocket) { this.uninstallEventHandlers() }\n this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols)\n this.installEventHandlers()\n this.monitor.start()\n return true\n }\n }\n\n close({allowReconnect} = {allowReconnect: true}) {\n if (!allowReconnect) { this.monitor.stop() }\n // Avoid closing websockets in a \"connecting\" state due to Safari 15.1+ bug. See: https://github.com/rails/rails/issues/43835#issuecomment-1002288478\n if (this.isOpen()) {\n return this.webSocket.close()\n }\n }\n\n reopen() {\n logger.log(`Reopening WebSocket, current state is ${this.getState()}`)\n if (this.isActive()) {\n try {\n return this.close()\n } catch (error) {\n logger.log(\"Failed to reopen WebSocket\", error)\n }\n finally {\n logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`)\n setTimeout(this.open, this.constructor.reopenDelay)\n }\n } else {\n return this.open()\n }\n }\n\n getProtocol() {\n if (this.webSocket) {\n return this.webSocket.protocol\n }\n }\n\n isOpen() {\n return this.isState(\"open\")\n }\n\n isActive() {\n return this.isState(\"open\", \"connecting\")\n }\n\n triedToReconnect() {\n return this.monitor.reconnectAttempts > 0\n }\n\n // Private\n\n isProtocolSupported() {\n return indexOf.call(supportedProtocols, this.getProtocol()) >= 0\n }\n\n isState(...states) {\n return indexOf.call(states, this.getState()) >= 0\n }\n\n getState() {\n if (this.webSocket) {\n for (let state in adapters.WebSocket) {\n if (adapters.WebSocket[state] === this.webSocket.readyState) {\n return state.toLowerCase()\n }\n }\n }\n return null\n }\n\n installEventHandlers() {\n for (let eventName in this.events) {\n const handler = this.events[eventName].bind(this)\n this.webSocket[`on${eventName}`] = handler\n }\n }\n\n uninstallEventHandlers() {\n for (let eventName in this.events) {\n this.webSocket[`on${eventName}`] = function() {}\n }\n }\n\n}\n\nConnection.reopenDelay = 500\n\nConnection.prototype.events = {\n message(event) {\n if (!this.isProtocolSupported()) { return }\n const {identifier, message, reason, reconnect, type} = JSON.parse(event.data)\n this.monitor.recordMessage()\n switch (type) {\n case message_types.welcome:\n if (this.triedToReconnect()) {\n this.reconnectAttempted = true\n }\n this.monitor.recordConnect()\n return this.subscriptions.reload()\n case message_types.disconnect:\n logger.log(`Disconnecting. Reason: ${reason}`)\n return this.close({allowReconnect: reconnect})\n case message_types.ping:\n return null\n case message_types.confirmation:\n this.subscriptions.confirmSubscription(identifier)\n if (this.reconnectAttempted) {\n this.reconnectAttempted = false\n return this.subscriptions.notify(identifier, \"connected\", {reconnected: true})\n } else {\n return this.subscriptions.notify(identifier, \"connected\", {reconnected: false})\n }\n case message_types.rejection:\n return this.subscriptions.reject(identifier)\n default:\n return this.subscriptions.notify(identifier, \"received\", message)\n }\n },\n\n open() {\n logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`)\n this.disconnected = false\n if (!this.isProtocolSupported()) {\n logger.log(\"Protocol is unsupported. Stopping monitor and disconnecting.\")\n return this.close({allowReconnect: false})\n }\n },\n\n close(event) {\n logger.log(\"WebSocket onclose event\")\n if (this.disconnected) { return }\n this.disconnected = true\n this.monitor.recordDisconnect()\n return this.subscriptions.notifyAll(\"disconnected\", {willAttemptReconnect: this.monitor.isRunning()})\n },\n\n error() {\n logger.log(\"WebSocket onerror event\")\n }\n}\n\nexport default Connection\n", "// A new subscription is created through the ActionCable.Subscriptions instance available on the consumer.\n// It provides a number of callbacks and a method for calling remote procedure calls on the corresponding\n// Channel instance on the server side.\n//\n// An example demonstrates the basic functionality:\n//\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\", {\n// connected() {\n// // Called once the subscription has been successfully completed\n// },\n//\n// disconnected({ willAttemptReconnect: boolean }) {\n// // Called when the client has disconnected with the server.\n// // The object will have an `willAttemptReconnect` property which\n// // says whether the client has the intention of attempting\n// // to reconnect.\n// },\n//\n// appear() {\n// this.perform('appear', {appearing_on: this.appearingOn()})\n// },\n//\n// away() {\n// this.perform('away')\n// },\n//\n// appearingOn() {\n// $('main').data('appearing-on')\n// }\n// })\n//\n// The methods #appear and #away forward their intent to the remote AppearanceChannel instance on the server\n// by calling the `perform` method with the first parameter being the action (which maps to AppearanceChannel#appear/away).\n// The second parameter is a hash that'll get JSON encoded and made available on the server in the data parameter.\n//\n// This is how the server component would look:\n//\n// class AppearanceChannel < ApplicationActionCable::Channel\n// def subscribed\n// current_user.appear\n// end\n//\n// def unsubscribed\n// current_user.disappear\n// end\n//\n// def appear(data)\n// current_user.appear on: data['appearing_on']\n// end\n//\n// def away\n// current_user.away\n// end\n// end\n//\n// The \"AppearanceChannel\" name is automatically mapped between the client-side subscription creation and the server-side Ruby class name.\n// The AppearanceChannel#appear/away public methods are exposed automatically to client-side invocation through the perform method.\n\nconst extend = function(object, properties) {\n if (properties != null) {\n for (let key in properties) {\n const value = properties[key]\n object[key] = value\n }\n }\n return object\n}\n\nexport default class Subscription {\n constructor(consumer, params = {}, mixin) {\n this.consumer = consumer\n this.identifier = JSON.stringify(params)\n extend(this, mixin)\n }\n\n // Perform a channel action with the optional data passed as an attribute\n perform(action, data = {}) {\n data.action = action\n return this.send(data)\n }\n\n send(data) {\n return this.consumer.send({command: \"message\", identifier: this.identifier, data: JSON.stringify(data)})\n }\n\n unsubscribe() {\n return this.consumer.subscriptions.remove(this)\n }\n}\n", "import logger from \"./logger\"\n\n// Responsible for ensuring channel subscribe command is confirmed, retrying until confirmation is received.\n// Internal class, not intended for direct user manipulation.\n\nclass SubscriptionGuarantor {\n constructor(subscriptions) {\n this.subscriptions = subscriptions\n this.pendingSubscriptions = []\n }\n\n guarantee(subscription) {\n if(this.pendingSubscriptions.indexOf(subscription) == -1){ \n logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`)\n this.pendingSubscriptions.push(subscription) \n }\n else {\n logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`)\n }\n this.startGuaranteeing()\n }\n\n forget(subscription) {\n logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`)\n this.pendingSubscriptions = (this.pendingSubscriptions.filter((s) => s !== subscription))\n }\n\n startGuaranteeing() {\n this.stopGuaranteeing()\n this.retrySubscribing()\n }\n \n stopGuaranteeing() {\n clearTimeout(this.retryTimeout)\n }\n\n retrySubscribing() {\n this.retryTimeout = setTimeout(() => {\n if (this.subscriptions && typeof(this.subscriptions.subscribe) === \"function\") {\n this.pendingSubscriptions.map((subscription) => {\n logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`)\n this.subscriptions.subscribe(subscription)\n })\n }\n }\n , 500)\n }\n}\n\nexport default SubscriptionGuarantor", "import Subscription from \"./subscription\"\nimport SubscriptionGuarantor from \"./subscription_guarantor\"\nimport logger from \"./logger\"\n\n// Collection class for creating (and internally managing) channel subscriptions.\n// The only method intended to be triggered by the user is ActionCable.Subscriptions#create,\n// and it should be called through the consumer like so:\n//\n// App = {}\n// App.cable = ActionCable.createConsumer(\"ws://example.com/accounts/1\")\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\")\n//\n// For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.\n\nexport default class Subscriptions {\n constructor(consumer) {\n this.consumer = consumer\n this.guarantor = new SubscriptionGuarantor(this)\n this.subscriptions = []\n }\n\n create(channelName, mixin) {\n const channel = channelName\n const params = typeof channel === \"object\" ? channel : {channel}\n const subscription = new Subscription(this.consumer, params, mixin)\n return this.add(subscription)\n }\n\n // Private\n\n add(subscription) {\n this.subscriptions.push(subscription)\n this.consumer.ensureActiveConnection()\n this.notify(subscription, \"initialized\")\n this.subscribe(subscription)\n return subscription\n }\n\n remove(subscription) {\n this.forget(subscription)\n if (!this.findAll(subscription.identifier).length) {\n this.sendCommand(subscription, \"unsubscribe\")\n }\n return subscription\n }\n\n reject(identifier) {\n return this.findAll(identifier).map((subscription) => {\n this.forget(subscription)\n this.notify(subscription, \"rejected\")\n return subscription\n })\n }\n\n forget(subscription) {\n this.guarantor.forget(subscription)\n this.subscriptions = (this.subscriptions.filter((s) => s !== subscription))\n return subscription\n }\n\n findAll(identifier) {\n return this.subscriptions.filter((s) => s.identifier === identifier)\n }\n\n reload() {\n return this.subscriptions.map((subscription) =>\n this.subscribe(subscription))\n }\n\n notifyAll(callbackName, ...args) {\n return this.subscriptions.map((subscription) =>\n this.notify(subscription, callbackName, ...args))\n }\n\n notify(subscription, callbackName, ...args) {\n let subscriptions\n if (typeof subscription === \"string\") {\n subscriptions = this.findAll(subscription)\n } else {\n subscriptions = [subscription]\n }\n\n return subscriptions.map((subscription) =>\n (typeof subscription[callbackName] === \"function\" ? subscription[callbackName](...args) : undefined))\n }\n\n subscribe(subscription) {\n if (this.sendCommand(subscription, \"subscribe\")) {\n this.guarantor.guarantee(subscription)\n }\n }\n\n confirmSubscription(identifier) {\n logger.log(`Subscription confirmed ${identifier}`)\n this.findAll(identifier).map((subscription) =>\n this.guarantor.forget(subscription))\n }\n\n sendCommand(subscription, command) {\n const {identifier} = subscription\n return this.consumer.send({command, identifier})\n }\n}\n", "import Connection from \"./connection\"\nimport Subscriptions from \"./subscriptions\"\n\n// The ActionCable.Consumer establishes the connection to a server-side Ruby Connection object. Once established,\n// the ActionCable.ConnectionMonitor will ensure that its properly maintained through heartbeats and checking for stale updates.\n// The Consumer instance is also the gateway to establishing subscriptions to desired channels through the #createSubscription\n// method.\n//\n// The following example shows how this can be set up:\n//\n// App = {}\n// App.cable = ActionCable.createConsumer(\"ws://example.com/accounts/1\")\n// App.appearance = App.cable.subscriptions.create(\"AppearanceChannel\")\n//\n// For more details on how you'd configure an actual channel subscription, see ActionCable.Subscription.\n//\n// When a consumer is created, it automatically connects with the server.\n//\n// To disconnect from the server, call\n//\n// App.cable.disconnect()\n//\n// and to restart the connection:\n//\n// App.cable.connect()\n//\n// Any channel subscriptions which existed prior to disconnecting will\n// automatically resubscribe.\n\nexport default class Consumer {\n constructor(url) {\n this._url = url\n this.subscriptions = new Subscriptions(this)\n this.connection = new Connection(this)\n this.subprotocols = []\n }\n\n get url() {\n return createWebSocketURL(this._url)\n }\n\n send(data) {\n return this.connection.send(data)\n }\n\n connect() {\n return this.connection.open()\n }\n\n disconnect() {\n return this.connection.close({allowReconnect: false})\n }\n\n ensureActiveConnection() {\n if (!this.connection.isActive()) {\n return this.connection.open()\n }\n }\n\n addSubProtocol(subprotocol) {\n this.subprotocols = [...this.subprotocols, subprotocol]\n }\n}\n\nexport function createWebSocketURL(url) {\n if (typeof url === \"function\") {\n url = url()\n }\n\n if (url && !/^wss?:/i.test(url)) {\n const a = document.createElement(\"a\")\n a.href = url\n // Fix populating Location properties in IE. Otherwise, protocol will be blank.\n a.href = a.href\n a.protocol = a.protocol.replace(\"http\", \"ws\")\n return a.href\n } else {\n return url\n }\n}\n", "import Connection from \"./connection\"\nimport ConnectionMonitor from \"./connection_monitor\"\nimport Consumer, { createWebSocketURL } from \"./consumer\"\nimport INTERNAL from \"./internal\"\nimport Subscription from \"./subscription\"\nimport Subscriptions from \"./subscriptions\"\nimport SubscriptionGuarantor from \"./subscription_guarantor\"\nimport adapters from \"./adapters\"\nimport logger from \"./logger\"\n\nexport {\n Connection,\n ConnectionMonitor,\n Consumer,\n INTERNAL,\n Subscription,\n Subscriptions,\n SubscriptionGuarantor,\n adapters,\n createWebSocketURL,\n logger,\n}\n\nexport function createConsumer(url = getConfig(\"url\") || INTERNAL.default_mount_path) {\n return new Consumer(url)\n}\n\nexport function getConfig(name) {\n const element = document.head.querySelector(`meta[name='action-cable-${name}']`)\n if (element) {\n return element.getAttribute(\"content\")\n }\n}\n", "const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n} = Object;\n\nlet { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports\nlet { apply, construct } = typeof Reflect !== 'undefined' && Reflect;\n\nif (!freeze) {\n freeze = function (x) {\n return x;\n };\n}\n\nif (!seal) {\n seal = function (x) {\n return x;\n };\n}\n\nif (!apply) {\n apply = function (fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n}\n\nif (!construct) {\n construct = function (Func, args) {\n return new Func(...args);\n };\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayIndexOf = unapply(Array.prototype.indexOf);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst arraySlice = unapply(Array.prototype.slice);\n\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\n\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n\nconst regExpTest = unapply(RegExp.prototype.test);\n\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply(func) {\n return (thisArg, ...args) => apply(func, thisArg, args);\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct(func) {\n return (...args) => construct(func, args);\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\nfunction addToSet(set, array, transformCaseFunc = stringToLowerCase) {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element] = true;\n }\n\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\nfunction cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\nfunction clone(object) {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (\n value &&\n typeof value === 'object' &&\n value.constructor === Object\n ) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n\n return newObject;\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue() {\n return null;\n }\n\n return fallbackValue;\n}\n\nexport {\n // Array\n arrayForEach,\n arrayIndexOf,\n arrayPop,\n arrayPush,\n arraySlice,\n // Object\n entries,\n freeze,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n isFrozen,\n setPrototypeOf,\n seal,\n clone,\n create,\n objectHasOwnProperty,\n // RegExp\n regExpTest,\n // String\n stringIndexOf,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringTrim,\n // Errors\n typeErrorCreate,\n // Other\n lookupGetter,\n addToSet,\n // Reflect\n unapply,\n unconstruct,\n};\n", "import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'a',\n 'abbr',\n 'acronym',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blink',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'content',\n 'data',\n 'datalist',\n 'dd',\n 'decorator',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'element',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'font',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hgroup',\n 'hr',\n 'html',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'marquee',\n 'menu',\n 'menuitem',\n 'meter',\n 'nav',\n 'nobr',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'shadow',\n 'small',\n 'source',\n 'spacer',\n 'span',\n 'strike',\n 'strong',\n 'style',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'tt',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n]);\n\n// SVG\nexport const svg = freeze([\n 'svg',\n 'a',\n 'altglyph',\n 'altglyphdef',\n 'altglyphitem',\n 'animatecolor',\n 'animatemotion',\n 'animatetransform',\n 'circle',\n 'clippath',\n 'defs',\n 'desc',\n 'ellipse',\n 'filter',\n 'font',\n 'g',\n 'glyph',\n 'glyphref',\n 'hkern',\n 'image',\n 'line',\n 'lineargradient',\n 'marker',\n 'mask',\n 'metadata',\n 'mpath',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialgradient',\n 'rect',\n 'stop',\n 'style',\n 'switch',\n 'symbol',\n 'text',\n 'textpath',\n 'title',\n 'tref',\n 'tspan',\n 'view',\n 'vkern',\n]);\n\nexport const svgFilters = freeze([\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n]);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nexport const svgDisallowed = freeze([\n 'animate',\n 'color-profile',\n 'cursor',\n 'discard',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignobject',\n 'hatch',\n 'hatchpath',\n 'mesh',\n 'meshgradient',\n 'meshpatch',\n 'meshrow',\n 'missing-glyph',\n 'script',\n 'set',\n 'solidcolor',\n 'unknown',\n 'use',\n]);\n\nexport const mathMl = freeze([\n 'math',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mglyph',\n 'mi',\n 'mlabeledtr',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'ms',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'mprescripts',\n]);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nexport const mathMlDisallowed = freeze([\n 'maction',\n 'maligngroup',\n 'malignmark',\n 'mlongdiv',\n 'mscarries',\n 'mscarry',\n 'msgroup',\n 'mstack',\n 'msline',\n 'msrow',\n 'semantics',\n 'annotation',\n 'annotation-xml',\n 'mprescripts',\n 'none',\n]);\n\nexport const text = freeze(['#text']);\n", "import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'accept',\n 'action',\n 'align',\n 'alt',\n 'autocapitalize',\n 'autocomplete',\n 'autopictureinpicture',\n 'autoplay',\n 'background',\n 'bgcolor',\n 'border',\n 'capture',\n 'cellpadding',\n 'cellspacing',\n 'checked',\n 'cite',\n 'class',\n 'clear',\n 'color',\n 'cols',\n 'colspan',\n 'controls',\n 'controlslist',\n 'coords',\n 'crossorigin',\n 'datetime',\n 'decoding',\n 'default',\n 'dir',\n 'disabled',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'download',\n 'draggable',\n 'enctype',\n 'enterkeyhint',\n 'face',\n 'for',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hreflang',\n 'id',\n 'inputmode',\n 'integrity',\n 'ismap',\n 'kind',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxlength',\n 'media',\n 'method',\n 'min',\n 'minlength',\n 'multiple',\n 'muted',\n 'name',\n 'nonce',\n 'noshade',\n 'novalidate',\n 'nowrap',\n 'open',\n 'optimum',\n 'pattern',\n 'placeholder',\n 'playsinline',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'poster',\n 'preload',\n 'pubdate',\n 'radiogroup',\n 'readonly',\n 'rel',\n 'required',\n 'rev',\n 'reversed',\n 'role',\n 'rows',\n 'rowspan',\n 'spellcheck',\n 'scope',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'span',\n 'srclang',\n 'start',\n 'src',\n 'srcset',\n 'step',\n 'style',\n 'summary',\n 'tabindex',\n 'title',\n 'translate',\n 'type',\n 'usemap',\n 'valign',\n 'value',\n 'width',\n 'wrap',\n 'xmlns',\n 'slot',\n]);\n\nexport const svg = freeze([\n 'accent-height',\n 'accumulate',\n 'additive',\n 'alignment-baseline',\n 'amplitude',\n 'ascent',\n 'attributename',\n 'attributetype',\n 'azimuth',\n 'basefrequency',\n 'baseline-shift',\n 'begin',\n 'bias',\n 'by',\n 'class',\n 'clip',\n 'clippathunits',\n 'clip-path',\n 'clip-rule',\n 'color',\n 'color-interpolation',\n 'color-interpolation-filters',\n 'color-profile',\n 'color-rendering',\n 'cx',\n 'cy',\n 'd',\n 'dx',\n 'dy',\n 'diffuseconstant',\n 'direction',\n 'display',\n 'divisor',\n 'dur',\n 'edgemode',\n 'elevation',\n 'end',\n 'exponent',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'filter',\n 'filterunits',\n 'flood-color',\n 'flood-opacity',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-weight',\n 'fx',\n 'fy',\n 'g1',\n 'g2',\n 'glyph-name',\n 'glyphref',\n 'gradientunits',\n 'gradienttransform',\n 'height',\n 'href',\n 'id',\n 'image-rendering',\n 'in',\n 'in2',\n 'intercept',\n 'k',\n 'k1',\n 'k2',\n 'k3',\n 'k4',\n 'kerning',\n 'keypoints',\n 'keysplines',\n 'keytimes',\n 'lang',\n 'lengthadjust',\n 'letter-spacing',\n 'kernelmatrix',\n 'kernelunitlength',\n 'lighting-color',\n 'local',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'markerheight',\n 'markerunits',\n 'markerwidth',\n 'maskcontentunits',\n 'maskunits',\n 'max',\n 'mask',\n 'media',\n 'method',\n 'mode',\n 'min',\n 'name',\n 'numoctaves',\n 'offset',\n 'operator',\n 'opacity',\n 'order',\n 'orient',\n 'orientation',\n 'origin',\n 'overflow',\n 'paint-order',\n 'path',\n 'pathlength',\n 'patterncontentunits',\n 'patterntransform',\n 'patternunits',\n 'points',\n 'preservealpha',\n 'preserveaspectratio',\n 'primitiveunits',\n 'r',\n 'rx',\n 'ry',\n 'radius',\n 'refx',\n 'refy',\n 'repeatcount',\n 'repeatdur',\n 'restart',\n 'result',\n 'rotate',\n 'scale',\n 'seed',\n 'shape-rendering',\n 'slope',\n 'specularconstant',\n 'specularexponent',\n 'spreadmethod',\n 'startoffset',\n 'stddeviation',\n 'stitchtiles',\n 'stop-color',\n 'stop-opacity',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-miterlimit',\n 'stroke-opacity',\n 'stroke',\n 'stroke-width',\n 'style',\n 'surfacescale',\n 'systemlanguage',\n 'tabindex',\n 'tablevalues',\n 'targetx',\n 'targety',\n 'transform',\n 'transform-origin',\n 'text-anchor',\n 'text-decoration',\n 'text-rendering',\n 'textlength',\n 'type',\n 'u1',\n 'u2',\n 'unicode',\n 'values',\n 'viewbox',\n 'visibility',\n 'version',\n 'vert-adv-y',\n 'vert-origin-x',\n 'vert-origin-y',\n 'width',\n 'word-spacing',\n 'wrap',\n 'writing-mode',\n 'xchannelselector',\n 'ychannelselector',\n 'x',\n 'x1',\n 'x2',\n 'xmlns',\n 'y',\n 'y1',\n 'y2',\n 'z',\n 'zoomandpan',\n]);\n\nexport const mathMl = freeze([\n 'accent',\n 'accentunder',\n 'align',\n 'bevelled',\n 'close',\n 'columnsalign',\n 'columnlines',\n 'columnspan',\n 'denomalign',\n 'depth',\n 'dir',\n 'display',\n 'displaystyle',\n 'encoding',\n 'fence',\n 'frame',\n 'height',\n 'href',\n 'id',\n 'largeop',\n 'length',\n 'linethickness',\n 'lspace',\n 'lquote',\n 'mathbackground',\n 'mathcolor',\n 'mathsize',\n 'mathvariant',\n 'maxsize',\n 'minsize',\n 'movablelimits',\n 'notation',\n 'numalign',\n 'open',\n 'rowalign',\n 'rowlines',\n 'rowspacing',\n 'rowspan',\n 'rspace',\n 'rquote',\n 'scriptlevel',\n 'scriptminsize',\n 'scriptsizemultiplier',\n 'selection',\n 'separator',\n 'separators',\n 'stretchy',\n 'subscriptshift',\n 'supscriptshift',\n 'symmetric',\n 'voffset',\n 'width',\n 'xmlns',\n]);\n\nexport const xml = freeze([\n 'xlink:href',\n 'xml:id',\n 'xlink:title',\n 'xml:space',\n 'xmlns:xlink',\n]);\n", "import { seal } from './utils.js';\n\n// eslint-disable-next-line unicorn/better-regex\nexport const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\nexport const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\nexport const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\nexport const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\nexport const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nexport const IS_ALLOWED_URI = seal(\n /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nexport const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nexport const ATTR_WHITESPACE = seal(\n /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nexport const DOCTYPE_NAME = seal(/^html$/i);\nexport const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n", "import * as TAGS from './tags.js';\nimport * as ATTRS from './attrs.js';\nimport * as EXPRESSIONS from './regexp.js';\nimport {\n addToSet,\n clone,\n entries,\n freeze,\n arrayForEach,\n arrayPop,\n arrayPush,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringIndexOf,\n stringTrim,\n regExpTest,\n typeErrorCreate,\n lookupGetter,\n create,\n objectHasOwnProperty,\n} from './utils.js';\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5, // Deprecated\n entityNode: 6, // Deprecated\n progressingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12, // Deprecated\n};\n\nconst getGlobal = function () {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function (trustedTypes, purifyHostElement) {\n if (\n typeof trustedTypes !== 'object' ||\n typeof trustedTypes.createPolicy !== 'function'\n ) {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n },\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn(\n 'TrustedTypes policy ' + policyName + ' could not be created.'\n );\n return null;\n }\n};\n\nfunction createDOMPurify(window = getGlobal()) {\n const DOMPurify = (root) => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = VERSION;\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n\n if (\n !window ||\n !window.document ||\n window.document.nodeType !== NODE_TYPE.document\n ) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n let { document } = window;\n\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes,\n } = window;\n\n const ElementPrototype = Element.prototype;\n\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const remove = lookupGetter(ElementPrototype, 'remove');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName,\n } = document;\n const { importNode } = originalDocument;\n\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported =\n typeof entries === 'function' &&\n typeof getParentNode === 'function' &&\n implementation &&\n implementation.createHTMLDocument !== undefined;\n\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT,\n } = EXPRESSIONS;\n\n let { IS_ALLOWED_URI } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [\n ...TAGS.html,\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.mathMl,\n ...TAGS.text,\n ]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [\n ...ATTRS.html,\n ...ATTRS.svg,\n ...ATTRS.mathMl,\n ...ATTRS.xml,\n ]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false,\n },\n })\n );\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with ... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, [\n 'annotation-xml',\n 'audio',\n 'colgroup',\n 'desc',\n 'foreignobject',\n 'head',\n 'iframe',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mtext',\n 'noembed',\n 'noframes',\n 'noscript',\n 'plaintext',\n 'script',\n 'style',\n 'svg',\n 'template',\n 'thead',\n 'title',\n 'video',\n 'xmp',\n ]);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, [\n 'audio',\n 'video',\n 'img',\n 'source',\n 'image',\n 'track',\n ]);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [\n 'alt',\n 'class',\n 'for',\n 'id',\n 'label',\n 'name',\n 'pattern',\n 'placeholder',\n 'role',\n 'summary',\n 'title',\n 'value',\n 'style',\n 'xmlns',\n ]);\n\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet(\n {},\n [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE],\n stringToString\n );\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n\n const isRegexOrFunction = function (testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function (cfg = {}) {\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1\n ? DEFAULT_PARSER_MEDIA_TYPE\n : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc =\n PARSER_MEDIA_TYPE === 'application/xhtml+xml'\n ? stringToString\n : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS')\n ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc)\n : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR')\n ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc)\n : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES')\n ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString)\n : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR')\n ? addToSet(\n clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS')\n ? addToSet(\n clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS')\n ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc)\n : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS')\n ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc)\n : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR')\n ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc)\n : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES')\n ? cfg.USE_PROFILES\n : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI = cfg.ALLOWED_URI_REGEXP || EXPRESSIONS.IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)\n ) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck =\n cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n\n if (\n cfg.CUSTOM_ELEMENT_HANDLING &&\n typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements ===\n 'boolean'\n ) {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =\n cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, TAGS.text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, TAGS.html);\n addToSet(ALLOWED_ATTR, ATTRS.html);\n }\n\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, TAGS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, TAGS.svgFilters);\n addToSet(ALLOWED_ATTR, ATTRS.svg);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, TAGS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.mathMl);\n addToSet(ALLOWED_ATTR, ATTRS.xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.'\n );\n }\n\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate(\n 'TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.'\n );\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(\n trustedTypes,\n currentScript\n );\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n\n CONFIG = cfg;\n };\n\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n ]);\n\n const HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [\n 'title',\n 'style',\n 'font',\n 'a',\n 'script',\n ]);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.svgDisallowed,\n ]);\n const ALL_MATHML_TAGS = addToSet({}, [\n ...TAGS.mathMl,\n ...TAGS.mathMlDisallowed,\n ]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function (element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template',\n };\n }\n\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return (\n tagName === 'svg' &&\n (parentTagName === 'annotation-xml' ||\n MATHML_TEXT_INTEGRATION_POINTS[parentTagName])\n );\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via . If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (\n parent.namespaceURI === SVG_NAMESPACE &&\n !HTML_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n if (\n parent.namespaceURI === MATHML_NAMESPACE &&\n !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]\n ) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return (\n !ALL_MATHML_TAGS[tagName] &&\n (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName])\n );\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n ALLOWED_NAMESPACES[element.namespaceURI]\n ) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function (node) {\n arrayPush(DOMPurify.removed, { element: node });\n\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n getParentNode(node).removeChild(node);\n } catch (_) {\n remove(node);\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function (name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node,\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node,\n });\n }\n\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function (dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n\n if (FORCE_BODY) {\n dirty = '' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n\n if (\n PARSER_MEDIA_TYPE === 'application/xhtml+xml' &&\n NAMESPACE === HTML_NAMESPACE\n ) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty =\n '' +\n dirty +\n '';\n }\n\n const dirtyPayload = trustedTypesPolicy\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT\n ? emptyHTML\n : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n\n const body = doc.body || doc.documentElement;\n\n if (dirty && leadingWhitespace) {\n body.insertBefore(\n document.createTextNode(leadingWhitespace),\n body.childNodes[0] || null\n );\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(\n doc,\n WHOLE_DOCUMENT ? 'html' : 'body'\n )[0];\n }\n\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function (root) {\n return createNodeIterator.call(\n root.ownerDocument || root,\n root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT |\n NodeFilter.SHOW_COMMENT |\n NodeFilter.SHOW_TEXT |\n NodeFilter.SHOW_PROCESSING_INSTRUCTION |\n NodeFilter.SHOW_CDATA_SECTION,\n null\n );\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function (elm) {\n return (\n elm instanceof HTMLFormElement &&\n (typeof elm.nodeName !== 'string' ||\n typeof elm.textContent !== 'string' ||\n typeof elm.removeChild !== 'function' ||\n !(elm.attributes instanceof NamedNodeMap) ||\n typeof elm.removeAttribute !== 'function' ||\n typeof elm.setAttribute !== 'function' ||\n typeof elm.namespaceURI !== 'string' ||\n typeof elm.insertBefore !== 'function' ||\n typeof elm.hasChildNodes !== 'function')\n );\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function (object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function (entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n\n arrayForEach(hooks[entryPoint], (hook) => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function (currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS,\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (\n currentNode.hasChildNodes() &&\n !_isNode(currentNode.firstElementChild) &&\n regExpTest(/<[/\\w]/g, currentNode.innerHTML) &&\n regExpTest(/<[/\\w]/g, currentNode.textContent)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any occurrence of processing instructions */\n if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (\n SAFE_FOR_XML &&\n currentNode.nodeType === NODE_TYPE.comment &&\n regExpTest(/<[/\\w]/g, currentNode.data)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)\n ) {\n return false;\n }\n\n if (\n CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)\n ) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n\n for (let i = childCount - 1; i >= 0; --i) {\n const childClone = cloneNode(childNodes[i], true);\n childClone.__removalCount = (currentNode.__removalCount || 0) + 1;\n parentNode.insertBefore(childClone, getNextSibling(currentNode));\n }\n }\n }\n\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if (\n (tagName === 'noscript' ||\n tagName === 'noembed' ||\n tagName === 'noframes') &&\n regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)\n ) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {\n /* Get the element's text content */\n content = currentNode.textContent;\n\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n content = stringReplace(content, expr, ' ');\n });\n\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function (lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (\n SANITIZE_DOM &&\n (lcName === 'id' || lcName === 'name') &&\n (value in document || value in formElement)\n ) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n if (\n ALLOW_DATA_ATTR &&\n !FORBID_ATTR[lcName] &&\n regExpTest(DATA_ATTR, lcName)\n ) {\n // This attribute is safe\n } else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) {\n // This attribute is safe\n /* Otherwise, check the name is permitted */\n } else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n (_isBasicCustomElement(lcTag) &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag))) &&\n ((CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName)) ||\n (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)))) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n (lcName === 'is' &&\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements &&\n ((CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp &&\n regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)) ||\n (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function &&\n CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))))\n ) {\n // If user has supplied a regexp or function in CUSTOM_ELEMENT_HANDLING.tagNameCheck, we need to also allow derived custom elements using the same tagName test.\n // Additionally, we need to allow attributes passing the CUSTOM_ELEMENT_HANDLING.attributeNameCheck user has configured, as custom elements can define these at their own discretion.\n } else {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } else if (URI_SAFE_ATTRIBUTES[lcName]) {\n // This attribute is safe\n /* Check no script, data or unknown possibly unsafe URI\n unless we know URI values are safe for that attribute */\n } else if (\n regExpTest(IS_ALLOWED_URI, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Keep image data URIs alive if src/xlink:href is allowed */\n /* Further prevent gadget XSS for dynamically built script tags */\n } else if (\n (lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') &&\n lcTag !== 'script' &&\n stringIndexOf(value, 'data:') === 0 &&\n DATA_URI_TAGS[lcTag]\n ) {\n // This attribute is safe\n /* Allow unknown protocols: This provides support for links that\n are handled by protocol handlers which may be unknown ahead of\n time, e.g. fb:, spotify: */\n } else if (\n ALLOW_UNKNOWN_PROTOCOLS &&\n !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))\n ) {\n // This attribute is safe\n /* Check for binary attributes */\n } else if (value) {\n return false;\n } else {\n // Binary attributes are safe at this point\n /* Anything else, presume unsafe, do not add it back */\n }\n\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function (tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function (currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n\n const { attributes } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR,\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const { name, namespaceURI, value: attrValue } = attr;\n const lcName = transformCaseFunc(name);\n\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Work around a security issue with comments inside attributes */\n if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\\/(style|title)/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Handle attributes that require Trusted Types */\n if (\n trustedTypesPolicy &&\n typeof trustedTypes === 'object' &&\n typeof trustedTypes.getAttributeType === 'function'\n ) {\n if (namespaceURI) {\n /* Namespaces are not yet supported, see https://bugs.chromium.org/p/chromium/issues/detail?id=1305293 */\n } else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML': {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n\n case 'TrustedScriptURL': {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n\n default: {\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n } else {\n arrayPop(DOMPurify.removed);\n }\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function (fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n\n while ((shadowNode = shadowIterator.nextNode())) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty, cfg = {}) {\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate(\n 'root node is forbidden and cannot be sanitized in-place'\n );\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (\n importedNode.nodeType === NODE_TYPE.element &&\n importedNode.nodeName === 'BODY'\n ) {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (\n !RETURN_DOM &&\n !SAFE_FOR_TEMPLATES &&\n !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1\n ) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(dirty)\n : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while ((currentNode = nodeIterator.nextNode())) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n\n return returnNode;\n }\n\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (\n WHOLE_DOCUMENT &&\n ALLOWED_TAGS['!doctype'] &&\n body.ownerDocument &&\n body.ownerDocument.doctype &&\n body.ownerDocument.doctype.name &&\n regExpTest(EXPRESSIONS.DOCTYPE_NAME, body.ownerDocument.doctype.name)\n ) {\n serializedHTML =\n '\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], (expr) => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE\n ? trustedTypesPolicy.createHTML(serializedHTML)\n : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function (cfg = {}) {\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n\n return DOMPurify;\n}\n\nexport default createDOMPurify();\n", "/*\n * Copyright (C) 2017 Alasdair Mercer, !ninja\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\n/**\n * A bare-bones constructor for surrogate prototype swapping.\n *\n * @private\n * @constructor\n */\nvar Constructor = /* istanbul ignore next */ function() {};\n/**\n * A reference to Object.prototype.hasOwnProperty.\n *\n * @private\n * @type {Function}\n */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n/**\n * A reference to Array.prototype.slice.\n *\n * @private\n * @type {Function}\n */\nvar slice = Array.prototype.slice;\n\n/**\n * Creates an object which inherits the given prototype.\n *\n * Optionally, the created object can be extended further with the specified properties.\n *\n * @param {Object} prototype - the prototype to be inherited by the created object\n * @param {Object} [properties] - the optional properties to be extended by the created object\n * @return {Object} The newly created object.\n * @private\n */\nfunction createObject(prototype, properties) {\n var result;\n /* istanbul ignore next */\n if (typeof Object.create === 'function') {\n result = Object.create(prototype);\n } else {\n Constructor.prototype = prototype;\n result = new Constructor();\n Constructor.prototype = null;\n }\n\n if (properties) {\n extendObject(true, result, properties);\n }\n\n return result;\n}\n\n/**\n * Extends the constructor to which this method is associated with the prototype and/or\n * statics provided.\n *\n * If name is provided, it will be used as the class name and can be accessed via a special\n * class_ property on the child constructor, otherwise the class name of the super constructor will be used\n * instead. The class name may also be used string representation for instances of the child constructor (via\n * toString), but this is not applicable to the lite version of Nevis.\n *\n * If constructor is provided, it will be used as the constructor for the child, otherwise a simple\n * constructor which only calls the super constructor will be used instead.\n *\n * The super constructor can be accessed via a special super_ property on the child constructor.\n *\n * @param {string} [name=this.class_] - the class name to be used for the child constructor\n * @param {Function} [constructor] - the constructor for the child\n * @param {Object} [prototype] - the prototype properties to be defined for the child\n * @param {Object} [statics] - the static properties to be defined for the child\n * @return {Function} The child constructor provided or the one created if none was given.\n * @public\n */\nfunction extend(name, constructor, prototype, statics) {\n var superConstructor = this;\n\n if (typeof name !== 'string') {\n statics = prototype;\n prototype = constructor;\n constructor = name;\n name = null;\n }\n\n if (typeof constructor !== 'function') {\n statics = prototype;\n prototype = constructor;\n constructor = function() {\n return superConstructor.apply(this, arguments);\n };\n }\n\n extendObject(false, constructor, superConstructor, statics);\n\n constructor.prototype = createObject(superConstructor.prototype, prototype);\n constructor.prototype.constructor = constructor;\n\n constructor.class_ = name || superConstructor.class_;\n constructor.super_ = superConstructor;\n\n return constructor;\n}\n\n/**\n * Extends the specified target object with the properties in each of the sources provided.\n *\n * if any source is null it will be ignored.\n *\n * @param {boolean} own - true to only copy own properties from sources onto\n * target; otherwise false\n * @param {Object} target - the target object which should be extended\n * @param {...Object} [sources] - the source objects whose properties are to be copied onto target\n * @return {void}\n * @private\n */\nfunction extendObject(own, target, sources) {\n sources = slice.call(arguments, 2);\n\n var property;\n var source;\n\n for (var i = 0, length = sources.length; i < length; i++) {\n source = sources[i];\n\n for (property in source) {\n if (!own || hasOwnProperty.call(source, property)) {\n target[property] = source[property];\n }\n }\n }\n}\n\nmodule.exports = extend;\n", "/*\n * Copyright (C) 2017 Alasdair Mercer, !ninja\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nvar extend = require('./extend');\n\n/**\n * The base class from which all others should extend.\n *\n * @public\n * @constructor\n */\nfunction Nevis() {}\nNevis.class_ = 'Nevis';\nNevis.super_ = Object;\n\n/**\n * Extends the constructor to which this method is associated with the prototype and/or\n * statics provided.\n *\n * If name is provided, it will be used as the class name and can be accessed via a special\n * class_ property on the child constructor, otherwise the class name of the super constructor will be used\n * instead. The class name may also be used string representation for instances of the child constructor (via\n * toString), but this is not applicable to the lite version of Nevis.\n *\n * If constructor is provided, it will be used as the constructor for the child, otherwise a simple\n * constructor which only calls the super constructor will be used instead.\n *\n * The super constructor can be accessed via a special super_ property on the child constructor.\n *\n * @param {string} [name=this.class_] - the class name to be used for the child constructor\n * @param {Function} [constructor] - the constructor for the child\n * @param {Object} [prototype] - the prototype properties to be defined for the child\n * @param {Object} [statics] - the static properties to be defined for the child\n * @return {Function} The child constructor provided or the one created if none was given.\n * @public\n * @static\n * @memberof Nevis\n */\nNevis.extend = extend;\n\nmodule.exports = Nevis;\n", "/*\n * Copyright (C) 2017 Alasdair Mercer, !ninja\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nmodule.exports = require('./src/nevis');\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Responsible for rendering a QR code {@link Frame} on a specific type of element.\n *\n * A renderer may be dependant on the rendering of another element, so the ordering of their execution is important.\n *\n * The rendering of a element can be deferred by disabling the renderer initially, however, any attempt get the element\n * from the renderer will result in it being immediately enabled and the element being rendered.\n *\n * @param {QRious} qrious - the {@link QRious} instance to be used\n * @param {*} element - the element onto which the QR code is to be rendered\n * @param {boolean} [enabled] - true this {@link Renderer} is enabled; otherwise false.\n * @public\n * @class\n * @extends Nevis\n */\nvar Renderer = Nevis.extend(function(qrious, element, enabled) {\n /**\n * The {@link QRious} instance.\n *\n * @protected\n * @type {QRious}\n * @memberof Renderer#\n */\n this.qrious = qrious;\n\n /**\n * The element onto which this {@link Renderer} is rendering the QR code.\n *\n * @protected\n * @type {*}\n * @memberof Renderer#\n */\n this.element = element;\n this.element.qrious = qrious;\n\n /**\n * Whether this {@link Renderer} is enabled.\n *\n * @protected\n * @type {boolean}\n * @memberof Renderer#\n */\n this.enabled = Boolean(enabled);\n}, {\n\n /**\n * Draws the specified QR code frame on the underlying element.\n *\n * Implementations of {@link Renderer} must override this method with their own specific logic.\n *\n * @param {Frame} frame - the {@link Frame} to be drawn\n * @return {void}\n * @protected\n * @abstract\n * @memberof Renderer#\n */\n draw: function(frame) {},\n\n /**\n * Returns the element onto which this {@link Renderer} is rendering the QR code.\n *\n * If this method is called while this {@link Renderer} is disabled, it will be immediately enabled and rendered\n * before the element is returned.\n *\n * @return {*} The element.\n * @public\n * @memberof Renderer#\n */\n getElement: function() {\n if (!this.enabled) {\n this.enabled = true;\n this.render();\n }\n\n return this.element;\n },\n\n /**\n * Calculates the size (in pixel units) to represent an individual module within the QR code based on the\n * frame provided.\n *\n * Any configured padding will be excluded from the returned size.\n *\n * The returned value will be at least one, even in cases where the size of the QR code does not fit its contents.\n * This is done so that the inevitable clipping is handled more gracefully since this way at least something is\n * displayed instead of just a blank space filled by the background color.\n *\n * @param {Frame} frame - the {@link Frame} from which the module size is to be derived\n * @return {number} The pixel size for each module in the QR code which will be no less than one.\n * @protected\n * @memberof Renderer#\n */\n getModuleSize: function(frame) {\n var qrious = this.qrious;\n var padding = qrious.padding || 0;\n var pixels = Math.floor((qrious.size - (padding * 2)) / frame.width);\n\n return Math.max(1, pixels);\n },\n\n /**\n * Calculates the offset/padding (in pixel units) to be inserted before the QR code based on the frame\n * provided.\n *\n * The returned value will be zero if there is no available offset or if the size of the QR code does not fit its\n * contents. It will never be a negative value. This is done so that the inevitable clipping appears more naturally\n * and it is not clipped from all directions.\n *\n * @param {Frame} frame - the {@link Frame} from which the offset is to be derived\n * @return {number} The pixel offset for the QR code which will be no less than zero.\n * @protected\n * @memberof Renderer#\n */\n getOffset: function(frame) {\n var qrious = this.qrious;\n var padding = qrious.padding;\n\n if (padding != null) {\n return padding;\n }\n\n var moduleSize = this.getModuleSize(frame);\n var offset = Math.floor((qrious.size - (moduleSize * frame.width)) / 2);\n\n return Math.max(0, offset);\n },\n\n /**\n * Renders a QR code on the underlying element based on the frame provided.\n *\n * @param {Frame} frame - the {@link Frame} to be rendered\n * @return {void}\n * @public\n * @memberof Renderer#\n */\n render: function(frame) {\n if (this.enabled) {\n this.resize();\n this.reset();\n this.draw(frame);\n }\n },\n\n /**\n * Resets the underlying element, effectively clearing any previously rendered QR code.\n *\n * Implementations of {@link Renderer} must override this method with their own specific logic.\n *\n * @return {void}\n * @protected\n * @abstract\n * @memberof Renderer#\n */\n reset: function() {},\n\n /**\n * Ensures that the size of the underlying element matches that defined on the associated {@link QRious} instance.\n *\n * Implementations of {@link Renderer} must override this method with their own specific logic.\n *\n * @return {void}\n * @protected\n * @abstract\n * @memberof Renderer#\n */\n resize: function() {}\n\n});\n\nmodule.exports = Renderer;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Renderer = require('./Renderer');\n\n/**\n * An implementation of {@link Renderer} for working with canvas elements.\n *\n * @public\n * @class\n * @extends Renderer\n */\nvar CanvasRenderer = Renderer.extend({\n\n /**\n * @override\n */\n draw: function(frame) {\n var i, j;\n var qrious = this.qrious;\n var moduleSize = this.getModuleSize(frame);\n var offset = this.getOffset(frame);\n var context = this.element.getContext('2d');\n\n context.fillStyle = qrious.foreground;\n context.globalAlpha = qrious.foregroundAlpha;\n\n for (i = 0; i < frame.width; i++) {\n for (j = 0; j < frame.width; j++) {\n if (frame.buffer[(j * frame.width) + i]) {\n context.fillRect((moduleSize * i) + offset, (moduleSize * j) + offset, moduleSize, moduleSize);\n }\n }\n }\n },\n\n /**\n * @override\n */\n reset: function() {\n var qrious = this.qrious;\n var context = this.element.getContext('2d');\n var size = qrious.size;\n\n context.lineWidth = 1;\n context.clearRect(0, 0, size, size);\n context.fillStyle = qrious.background;\n context.globalAlpha = qrious.backgroundAlpha;\n context.fillRect(0, 0, size, size);\n },\n\n /**\n * @override\n */\n resize: function() {\n var element = this.element;\n\n element.width = element.height = this.qrious.size;\n }\n\n});\n\nmodule.exports = CanvasRenderer;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\n/* eslint no-multi-spaces: \"off\" */\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Contains alignment pattern information.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar Alignment = Nevis.extend(null, {\n\n /**\n * The alignment pattern block.\n *\n * @public\n * @static\n * @type {number[]}\n * @memberof Alignment\n */\n BLOCK: [\n 0, 11, 15, 19, 23, 27, 31,\n 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,\n 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28\n ]\n\n});\n\nmodule.exports = Alignment;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\n/* eslint no-multi-spaces: \"off\" */\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Contains error correction information.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar ErrorCorrection = Nevis.extend(null, {\n\n /**\n * The error correction blocks.\n *\n * There are four elements per version. The first two indicate the number of blocks, then the data width, and finally\n * the ECC width.\n *\n * @public\n * @static\n * @type {number[]}\n * @memberof ErrorCorrection\n */\n BLOCKS: [\n 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,\n 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,\n 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,\n 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,\n 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,\n 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,\n 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,\n 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,\n 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,\n 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,\n 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,\n 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,\n 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,\n 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,\n 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,\n 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30,\n 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28,\n 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28,\n 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26,\n 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28,\n 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,\n 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24,\n 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30,\n 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30,\n 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30,\n 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,\n 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30,\n 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30,\n 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30,\n 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30,\n 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30,\n 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30,\n 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30,\n 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,\n 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30,\n 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30,\n 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30,\n 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30,\n 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30,\n 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30\n ],\n\n /**\n * The final format bits with mask (level << 3 | mask).\n *\n * @public\n * @static\n * @type {number[]}\n * @memberof ErrorCorrection\n */\n FINAL_FORMAT: [\n // L\n 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976,\n // M\n 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0,\n // Q\n 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed,\n // H\n 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b\n ],\n\n /**\n * A map of human-readable ECC levels.\n *\n * @public\n * @static\n * @type {Object.}\n * @memberof ErrorCorrection\n */\n LEVELS: {\n L: 1,\n M: 2,\n Q: 3,\n H: 4\n }\n\n});\n\nmodule.exports = ErrorCorrection;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Contains Galois field information.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar Galois = Nevis.extend(null, {\n\n /**\n * The Galois field exponent table.\n *\n * @public\n * @static\n * @type {number[]}\n * @memberof Galois\n */\n EXPONENT: [\n 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,\n 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,\n 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,\n 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,\n 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,\n 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,\n 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,\n 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,\n 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,\n 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,\n 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,\n 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,\n 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,\n 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,\n 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,\n 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00\n ],\n\n /**\n * The Galois field log table.\n *\n * @public\n * @static\n * @type {number[]}\n * @memberof Galois\n */\n LOG: [\n 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,\n 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,\n 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,\n 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,\n 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,\n 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,\n 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,\n 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,\n 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,\n 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,\n 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,\n 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,\n 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,\n 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,\n 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,\n 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf\n ]\n\n});\n\nmodule.exports = Galois;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Contains version pattern information.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar Version = Nevis.extend(null, {\n\n /**\n * The version pattern block.\n *\n * @public\n * @static\n * @type {number[]}\n * @memberof Version\n */\n BLOCK: [\n 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, 0x928, 0xb78, 0x45d, 0xa17, 0x532,\n 0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5,\n 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69\n ]\n\n});\n\nmodule.exports = Version;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\nvar Alignment = require('./Alignment');\nvar ErrorCorrection = require('./ErrorCorrection');\nvar Galois = require('./Galois');\nvar Version = require('./Version');\n\n/**\n * Generates information for a QR code frame based on a specific value to be encoded.\n *\n * @param {Frame~Options} options - the options to be used\n * @public\n * @class\n * @extends Nevis\n */\nvar Frame = Nevis.extend(function(options) {\n var dataBlock, eccBlock, index, neccBlock1, neccBlock2;\n var valueLength = options.value.length;\n\n this._badness = [];\n this._level = ErrorCorrection.LEVELS[options.level];\n this._polynomial = [];\n this._value = options.value;\n this._version = 0;\n this._stringBuffer = [];\n\n while (this._version < 40) {\n this._version++;\n\n index = ((this._level - 1) * 4) + ((this._version - 1) * 16);\n\n neccBlock1 = ErrorCorrection.BLOCKS[index++];\n neccBlock2 = ErrorCorrection.BLOCKS[index++];\n dataBlock = ErrorCorrection.BLOCKS[index++];\n eccBlock = ErrorCorrection.BLOCKS[index];\n\n index = (dataBlock * (neccBlock1 + neccBlock2)) + neccBlock2 - 3 + (this._version <= 9);\n\n if (valueLength <= index) {\n break;\n }\n }\n\n this._dataBlock = dataBlock;\n this._eccBlock = eccBlock;\n this._neccBlock1 = neccBlock1;\n this._neccBlock2 = neccBlock2;\n\n /**\n * The data width is based on version.\n *\n * @public\n * @type {number}\n * @memberof Frame#\n */\n // FIXME: Ensure that it fits instead of being truncated.\n var width = this.width = 17 + (4 * this._version);\n\n /**\n * The image buffer.\n *\n * @public\n * @type {number[]}\n * @memberof Frame#\n */\n this.buffer = Frame._createArray(width * width);\n\n this._ecc = Frame._createArray(dataBlock + ((dataBlock + eccBlock) * (neccBlock1 + neccBlock2)) + neccBlock2);\n this._mask = Frame._createArray(((width * (width + 1)) + 1) / 2);\n\n this._insertFinders();\n this._insertAlignments();\n\n // Insert single foreground cell.\n this.buffer[8 + (width * (width - 8))] = 1;\n\n this._insertTimingGap();\n this._reverseMask();\n this._insertTimingRowAndColumn();\n this._insertVersion();\n this._syncMask();\n this._convertBitStream(valueLength);\n this._calculatePolynomial();\n this._appendEccToData();\n this._interleaveBlocks();\n this._pack();\n this._finish();\n}, {\n\n _addAlignment: function(x, y) {\n var i;\n var buffer = this.buffer;\n var width = this.width;\n\n buffer[x + (width * y)] = 1;\n\n for (i = -2; i < 2; i++) {\n buffer[x + i + (width * (y - 2))] = 1;\n buffer[x - 2 + (width * (y + i + 1))] = 1;\n buffer[x + 2 + (width * (y + i))] = 1;\n buffer[x + i + 1 + (width * (y + 2))] = 1;\n }\n\n for (i = 0; i < 2; i++) {\n this._setMask(x - 1, y + i);\n this._setMask(x + 1, y - i);\n this._setMask(x - i, y - 1);\n this._setMask(x + i, y + 1);\n }\n },\n\n _appendData: function(data, dataLength, ecc, eccLength) {\n var bit, i, j;\n var polynomial = this._polynomial;\n var stringBuffer = this._stringBuffer;\n\n for (i = 0; i < eccLength; i++) {\n stringBuffer[ecc + i] = 0;\n }\n\n for (i = 0; i < dataLength; i++) {\n bit = Galois.LOG[stringBuffer[data + i] ^ stringBuffer[ecc]];\n\n if (bit !== 255) {\n for (j = 1; j < eccLength; j++) {\n stringBuffer[ecc + j - 1] = stringBuffer[ecc + j] ^\n Galois.EXPONENT[Frame._modN(bit + polynomial[eccLength - j])];\n }\n } else {\n for (j = ecc; j < ecc + eccLength; j++) {\n stringBuffer[j] = stringBuffer[j + 1];\n }\n }\n\n stringBuffer[ecc + eccLength - 1] = bit === 255 ? 0 : Galois.EXPONENT[Frame._modN(bit + polynomial[0])];\n }\n },\n\n _appendEccToData: function() {\n var i;\n var data = 0;\n var dataBlock = this._dataBlock;\n var ecc = this._calculateMaxLength();\n var eccBlock = this._eccBlock;\n\n for (i = 0; i < this._neccBlock1; i++) {\n this._appendData(data, dataBlock, ecc, eccBlock);\n\n data += dataBlock;\n ecc += eccBlock;\n }\n\n for (i = 0; i < this._neccBlock2; i++) {\n this._appendData(data, dataBlock + 1, ecc, eccBlock);\n\n data += dataBlock + 1;\n ecc += eccBlock;\n }\n },\n\n _applyMask: function(mask) {\n var r3x, r3y, x, y;\n var buffer = this.buffer;\n var width = this.width;\n\n switch (mask) {\n case 0:\n for (y = 0; y < width; y++) {\n for (x = 0; x < width; x++) {\n if (!((x + y) & 1) && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 1:\n for (y = 0; y < width; y++) {\n for (x = 0; x < width; x++) {\n if (!(y & 1) && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 2:\n for (y = 0; y < width; y++) {\n for (r3x = 0, x = 0; x < width; x++, r3x++) {\n if (r3x === 3) {\n r3x = 0;\n }\n\n if (!r3x && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 3:\n for (r3y = 0, y = 0; y < width; y++, r3y++) {\n if (r3y === 3) {\n r3y = 0;\n }\n\n for (r3x = r3y, x = 0; x < width; x++, r3x++) {\n if (r3x === 3) {\n r3x = 0;\n }\n\n if (!r3x && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 4:\n for (y = 0; y < width; y++) {\n for (r3x = 0, r3y = (y >> 1) & 1, x = 0; x < width; x++, r3x++) {\n if (r3x === 3) {\n r3x = 0;\n r3y = !r3y;\n }\n\n if (!r3y && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 5:\n for (r3y = 0, y = 0; y < width; y++, r3y++) {\n if (r3y === 3) {\n r3y = 0;\n }\n\n for (r3x = 0, x = 0; x < width; x++, r3x++) {\n if (r3x === 3) {\n r3x = 0;\n }\n\n if (!((x & y & 1) + !(!r3x | !r3y)) && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 6:\n for (r3y = 0, y = 0; y < width; y++, r3y++) {\n if (r3y === 3) {\n r3y = 0;\n }\n\n for (r3x = 0, x = 0; x < width; x++, r3x++) {\n if (r3x === 3) {\n r3x = 0;\n }\n\n if (!((x & y & 1) + (r3x && r3x === r3y) & 1) && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n case 7:\n for (r3y = 0, y = 0; y < width; y++, r3y++) {\n if (r3y === 3) {\n r3y = 0;\n }\n\n for (r3x = 0, x = 0; x < width; x++, r3x++) {\n if (r3x === 3) {\n r3x = 0;\n }\n\n if (!((r3x && r3x === r3y) + (x + y & 1) & 1) && !this._isMasked(x, y)) {\n buffer[x + (y * width)] ^= 1;\n }\n }\n }\n\n break;\n }\n },\n\n _calculateMaxLength: function() {\n return (this._dataBlock * (this._neccBlock1 + this._neccBlock2)) + this._neccBlock2;\n },\n\n _calculatePolynomial: function() {\n var i, j;\n var eccBlock = this._eccBlock;\n var polynomial = this._polynomial;\n\n polynomial[0] = 1;\n\n for (i = 0; i < eccBlock; i++) {\n polynomial[i + 1] = 1;\n\n for (j = i; j > 0; j--) {\n polynomial[j] = polynomial[j] ? polynomial[j - 1] ^\n Galois.EXPONENT[Frame._modN(Galois.LOG[polynomial[j]] + i)] : polynomial[j - 1];\n }\n\n polynomial[0] = Galois.EXPONENT[Frame._modN(Galois.LOG[polynomial[0]] + i)];\n }\n\n // Use logs for generator polynomial to save calculation step.\n for (i = 0; i <= eccBlock; i++) {\n polynomial[i] = Galois.LOG[polynomial[i]];\n }\n },\n\n _checkBadness: function() {\n var b, b1, h, x, y;\n var bad = 0;\n var badness = this._badness;\n var buffer = this.buffer;\n var width = this.width;\n\n // Blocks of same colour.\n for (y = 0; y < width - 1; y++) {\n for (x = 0; x < width - 1; x++) {\n // All foreground colour.\n if ((buffer[x + (width * y)] &&\n buffer[x + 1 + (width * y)] &&\n buffer[x + (width * (y + 1))] &&\n buffer[x + 1 + (width * (y + 1))]) ||\n // All background colour.\n !(buffer[x + (width * y)] ||\n buffer[x + 1 + (width * y)] ||\n buffer[x + (width * (y + 1))] ||\n buffer[x + 1 + (width * (y + 1))])) {\n bad += Frame.N2;\n }\n }\n }\n\n var bw = 0;\n\n // X runs.\n for (y = 0; y < width; y++) {\n h = 0;\n\n badness[0] = 0;\n\n for (b = 0, x = 0; x < width; x++) {\n b1 = buffer[x + (width * y)];\n\n if (b === b1) {\n badness[h]++;\n } else {\n badness[++h] = 1;\n }\n\n b = b1;\n bw += b ? 1 : -1;\n }\n\n bad += this._getBadness(h);\n }\n\n if (bw < 0) {\n bw = -bw;\n }\n\n var count = 0;\n var big = bw;\n big += big << 2;\n big <<= 1;\n\n while (big > width * width) {\n big -= width * width;\n count++;\n }\n\n bad += count * Frame.N4;\n\n // Y runs.\n for (x = 0; x < width; x++) {\n h = 0;\n\n badness[0] = 0;\n\n for (b = 0, y = 0; y < width; y++) {\n b1 = buffer[x + (width * y)];\n\n if (b === b1) {\n badness[h]++;\n } else {\n badness[++h] = 1;\n }\n\n b = b1;\n }\n\n bad += this._getBadness(h);\n }\n\n return bad;\n },\n\n _convertBitStream: function(length) {\n var bit, i;\n var ecc = this._ecc;\n var version = this._version;\n\n // Convert string to bit stream. 8-bit data to QR-coded 8-bit data (numeric, alphanumeric, or kanji not supported).\n for (i = 0; i < length; i++) {\n ecc[i] = this._value.charCodeAt(i);\n }\n\n var stringBuffer = this._stringBuffer = ecc.slice();\n var maxLength = this._calculateMaxLength();\n\n if (length >= maxLength - 2) {\n length = maxLength - 2;\n\n if (version > 9) {\n length--;\n }\n }\n\n // Shift and re-pack to insert length prefix.\n var index = length;\n\n if (version > 9) {\n stringBuffer[index + 2] = 0;\n stringBuffer[index + 3] = 0;\n\n while (index--) {\n bit = stringBuffer[index];\n\n stringBuffer[index + 3] |= 255 & (bit << 4);\n stringBuffer[index + 2] = bit >> 4;\n }\n\n stringBuffer[2] |= 255 & (length << 4);\n stringBuffer[1] = length >> 4;\n stringBuffer[0] = 0x40 | (length >> 12);\n } else {\n stringBuffer[index + 1] = 0;\n stringBuffer[index + 2] = 0;\n\n while (index--) {\n bit = stringBuffer[index];\n\n stringBuffer[index + 2] |= 255 & (bit << 4);\n stringBuffer[index + 1] = bit >> 4;\n }\n\n stringBuffer[1] |= 255 & (length << 4);\n stringBuffer[0] = 0x40 | (length >> 4);\n }\n\n // Fill to end with pad pattern.\n index = length + 3 - (version < 10);\n\n while (index < maxLength) {\n stringBuffer[index++] = 0xec;\n stringBuffer[index++] = 0x11;\n }\n },\n\n _getBadness: function(length) {\n var i;\n var badRuns = 0;\n var badness = this._badness;\n\n for (i = 0; i <= length; i++) {\n if (badness[i] >= 5) {\n badRuns += Frame.N1 + badness[i] - 5;\n }\n }\n\n // FBFFFBF as in finder.\n for (i = 3; i < length - 1; i += 2) {\n if (badness[i - 2] === badness[i + 2] &&\n badness[i + 2] === badness[i - 1] &&\n badness[i - 1] === badness[i + 1] &&\n badness[i - 1] * 3 === badness[i] &&\n // Background around the foreground pattern? Not part of the specs.\n (badness[i - 3] === 0 || i + 3 > length ||\n badness[i - 3] * 3 >= badness[i] * 4 ||\n badness[i + 3] * 3 >= badness[i] * 4)) {\n badRuns += Frame.N3;\n }\n }\n\n return badRuns;\n },\n\n _finish: function() {\n // Save pre-mask copy of frame.\n this._stringBuffer = this.buffer.slice();\n\n var currentMask, i;\n var bit = 0;\n var mask = 30000;\n\n /*\n * Using for instead of while since in original Arduino code if an early mask was \"good enough\" it wouldn't try for\n * a better one since they get more complex and take longer.\n */\n for (i = 0; i < 8; i++) {\n // Returns foreground-background imbalance.\n this._applyMask(i);\n\n currentMask = this._checkBadness();\n\n // Is current mask better than previous best?\n if (currentMask < mask) {\n mask = currentMask;\n bit = i;\n }\n\n // Don't increment \"i\" to a void redoing mask.\n if (bit === 7) {\n break;\n }\n\n // Reset for next pass.\n this.buffer = this._stringBuffer.slice();\n }\n\n // Redo best mask as none were \"good enough\" (i.e. last wasn't bit).\n if (bit !== i) {\n this._applyMask(bit);\n }\n\n // Add in final mask/ECC level bytes.\n mask = ErrorCorrection.FINAL_FORMAT[bit + (this._level - 1 << 3)];\n\n var buffer = this.buffer;\n var width = this.width;\n\n // Low byte.\n for (i = 0; i < 8; i++, mask >>= 1) {\n if (mask & 1) {\n buffer[width - 1 - i + (width * 8)] = 1;\n\n if (i < 6) {\n buffer[8 + (width * i)] = 1;\n } else {\n buffer[8 + (width * (i + 1))] = 1;\n }\n }\n }\n\n // High byte.\n for (i = 0; i < 7; i++, mask >>= 1) {\n if (mask & 1) {\n buffer[8 + (width * (width - 7 + i))] = 1;\n\n if (i) {\n buffer[6 - i + (width * 8)] = 1;\n } else {\n buffer[7 + (width * 8)] = 1;\n }\n }\n }\n },\n\n _interleaveBlocks: function() {\n var i, j;\n var dataBlock = this._dataBlock;\n var ecc = this._ecc;\n var eccBlock = this._eccBlock;\n var k = 0;\n var maxLength = this._calculateMaxLength();\n var neccBlock1 = this._neccBlock1;\n var neccBlock2 = this._neccBlock2;\n var stringBuffer = this._stringBuffer;\n\n for (i = 0; i < dataBlock; i++) {\n for (j = 0; j < neccBlock1; j++) {\n ecc[k++] = stringBuffer[i + (j * dataBlock)];\n }\n\n for (j = 0; j < neccBlock2; j++) {\n ecc[k++] = stringBuffer[(neccBlock1 * dataBlock) + i + (j * (dataBlock + 1))];\n }\n }\n\n for (j = 0; j < neccBlock2; j++) {\n ecc[k++] = stringBuffer[(neccBlock1 * dataBlock) + i + (j * (dataBlock + 1))];\n }\n\n for (i = 0; i < eccBlock; i++) {\n for (j = 0; j < neccBlock1 + neccBlock2; j++) {\n ecc[k++] = stringBuffer[maxLength + i + (j * eccBlock)];\n }\n }\n\n this._stringBuffer = ecc;\n },\n\n _insertAlignments: function() {\n var i, x, y;\n var version = this._version;\n var width = this.width;\n\n if (version > 1) {\n i = Alignment.BLOCK[version];\n y = width - 7;\n\n for (;;) {\n x = width - 7;\n\n while (x > i - 3) {\n this._addAlignment(x, y);\n\n if (x < i) {\n break;\n }\n\n x -= i;\n }\n\n if (y <= i + 9) {\n break;\n }\n\n y -= i;\n\n this._addAlignment(6, y);\n this._addAlignment(y, 6);\n }\n }\n },\n\n _insertFinders: function() {\n var i, j, x, y;\n var buffer = this.buffer;\n var width = this.width;\n\n for (i = 0; i < 3; i++) {\n j = 0;\n y = 0;\n\n if (i === 1) {\n j = width - 7;\n }\n if (i === 2) {\n y = width - 7;\n }\n\n buffer[y + 3 + (width * (j + 3))] = 1;\n\n for (x = 0; x < 6; x++) {\n buffer[y + x + (width * j)] = 1;\n buffer[y + (width * (j + x + 1))] = 1;\n buffer[y + 6 + (width * (j + x))] = 1;\n buffer[y + x + 1 + (width * (j + 6))] = 1;\n }\n\n for (x = 1; x < 5; x++) {\n this._setMask(y + x, j + 1);\n this._setMask(y + 1, j + x + 1);\n this._setMask(y + 5, j + x);\n this._setMask(y + x + 1, j + 5);\n }\n\n for (x = 2; x < 4; x++) {\n buffer[y + x + (width * (j + 2))] = 1;\n buffer[y + 2 + (width * (j + x + 1))] = 1;\n buffer[y + 4 + (width * (j + x))] = 1;\n buffer[y + x + 1 + (width * (j + 4))] = 1;\n }\n }\n },\n\n _insertTimingGap: function() {\n var x, y;\n var width = this.width;\n\n for (y = 0; y < 7; y++) {\n this._setMask(7, y);\n this._setMask(width - 8, y);\n this._setMask(7, y + width - 7);\n }\n\n for (x = 0; x < 8; x++) {\n this._setMask(x, 7);\n this._setMask(x + width - 8, 7);\n this._setMask(x, width - 8);\n }\n },\n\n _insertTimingRowAndColumn: function() {\n var x;\n var buffer = this.buffer;\n var width = this.width;\n\n for (x = 0; x < width - 14; x++) {\n if (x & 1) {\n this._setMask(8 + x, 6);\n this._setMask(6, 8 + x);\n } else {\n buffer[8 + x + (width * 6)] = 1;\n buffer[6 + (width * (8 + x))] = 1;\n }\n }\n },\n\n _insertVersion: function() {\n var i, j, x, y;\n var buffer = this.buffer;\n var version = this._version;\n var width = this.width;\n\n if (version > 6) {\n i = Version.BLOCK[version - 7];\n j = 17;\n\n for (x = 0; x < 6; x++) {\n for (y = 0; y < 3; y++, j--) {\n if (1 & (j > 11 ? version >> j - 12 : i >> j)) {\n buffer[5 - x + (width * (2 - y + width - 11))] = 1;\n buffer[2 - y + width - 11 + (width * (5 - x))] = 1;\n } else {\n this._setMask(5 - x, 2 - y + width - 11);\n this._setMask(2 - y + width - 11, 5 - x);\n }\n }\n }\n }\n },\n\n _isMasked: function(x, y) {\n var bit = Frame._getMaskBit(x, y);\n\n return this._mask[bit] === 1;\n },\n\n _pack: function() {\n var bit, i, j;\n var k = 1;\n var v = 1;\n var width = this.width;\n var x = width - 1;\n var y = width - 1;\n\n // Interleaved data and ECC codes.\n var length = ((this._dataBlock + this._eccBlock) * (this._neccBlock1 + this._neccBlock2)) + this._neccBlock2;\n\n for (i = 0; i < length; i++) {\n bit = this._stringBuffer[i];\n\n for (j = 0; j < 8; j++, bit <<= 1) {\n if (0x80 & bit) {\n this.buffer[x + (width * y)] = 1;\n }\n\n // Find next fill position.\n do {\n if (v) {\n x--;\n } else {\n x++;\n\n if (k) {\n if (y !== 0) {\n y--;\n } else {\n x -= 2;\n k = !k;\n\n if (x === 6) {\n x--;\n y = 9;\n }\n }\n } else if (y !== width - 1) {\n y++;\n } else {\n x -= 2;\n k = !k;\n\n if (x === 6) {\n x--;\n y -= 8;\n }\n }\n }\n\n v = !v;\n } while (this._isMasked(x, y));\n }\n }\n },\n\n _reverseMask: function() {\n var x, y;\n var width = this.width;\n\n for (x = 0; x < 9; x++) {\n this._setMask(x, 8);\n }\n\n for (x = 0; x < 8; x++) {\n this._setMask(x + width - 8, 8);\n this._setMask(8, x);\n }\n\n for (y = 0; y < 7; y++) {\n this._setMask(8, y + width - 7);\n }\n },\n\n _setMask: function(x, y) {\n var bit = Frame._getMaskBit(x, y);\n\n this._mask[bit] = 1;\n },\n\n _syncMask: function() {\n var x, y;\n var width = this.width;\n\n for (y = 0; y < width; y++) {\n for (x = 0; x <= y; x++) {\n if (this.buffer[x + (width * y)]) {\n this._setMask(x, y);\n }\n }\n }\n }\n\n}, {\n\n _createArray: function(length) {\n var i;\n var array = [];\n\n for (i = 0; i < length; i++) {\n array[i] = 0;\n }\n\n return array;\n },\n\n _getMaskBit: function(x, y) {\n var bit;\n\n if (x > y) {\n bit = x;\n x = y;\n y = bit;\n }\n\n bit = y;\n bit += y * y;\n bit >>= 1;\n bit += x;\n\n return bit;\n },\n\n _modN: function(x) {\n while (x >= 255) {\n x -= 255;\n x = (x >> 8) + (x & 255);\n }\n\n return x;\n },\n\n // *Badness* coefficients.\n N1: 3,\n N2: 3,\n N3: 40,\n N4: 10\n\n});\n\nmodule.exports = Frame;\n\n/**\n * The options used by {@link Frame}.\n *\n * @typedef {Object} Frame~Options\n * @property {string} level - The ECC level to be used.\n * @property {string} value - The value to be encoded.\n */\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Renderer = require('./Renderer');\n\n/**\n * An implementation of {@link Renderer} for working with img elements.\n *\n * This depends on {@link CanvasRenderer} being executed first as this implementation simply applies the data URL from\n * the rendered canvas element as the src for the img element being rendered.\n *\n * @public\n * @class\n * @extends Renderer\n */\nvar ImageRenderer = Renderer.extend({\n\n /**\n * @override\n */\n draw: function() {\n this.element.src = this.qrious.toDataURL();\n },\n\n /**\n * @override\n */\n reset: function() {\n this.element.src = '';\n },\n\n /**\n * @override\n */\n resize: function() {\n var element = this.element;\n\n element.width = element.height = this.qrious.size;\n }\n\n});\n\nmodule.exports = ImageRenderer;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Defines an available option while also configuring how values are applied to the target object.\n *\n * Optionally, a default value can be specified as well a value transformer for greater control over how the option\n * value is applied.\n *\n * If no value transformer is specified, then any specified option will be applied directly. All values are maintained\n * on the target object itself as a field using the option name prefixed with a single underscore.\n *\n * When an option is specified as modifiable, the {@link OptionManager} will be required to include a setter for the\n * property that is defined on the target object that uses the option name.\n *\n * @param {string} name - the name to be used\n * @param {boolean} [modifiable] - true if the property defined on target objects should include a setter;\n * otherwise false\n * @param {*} [defaultValue] - the default value to be used\n * @param {Option~ValueTransformer} [valueTransformer] - the value transformer to be used\n * @public\n * @class\n * @extends Nevis\n */\nvar Option = Nevis.extend(function(name, modifiable, defaultValue, valueTransformer) {\n /**\n * The name for this {@link Option}.\n *\n * @public\n * @type {string}\n * @memberof Option#\n */\n this.name = name;\n\n /**\n * Whether a setter should be included on the property defined on target objects for this {@link Option}.\n *\n * @public\n * @type {boolean}\n * @memberof Option#\n */\n this.modifiable = Boolean(modifiable);\n\n /**\n * The default value for this {@link Option}.\n *\n * @public\n * @type {*}\n * @memberof Option#\n */\n this.defaultValue = defaultValue;\n\n this._valueTransformer = valueTransformer;\n}, {\n\n /**\n * Transforms the specified value so that it can be applied for this {@link Option}.\n *\n * If a value transformer has been specified for this {@link Option}, it will be called upon to transform\n * value. Otherwise, value will be returned directly.\n *\n * @param {*} value - the value to be transformed\n * @return {*} The transformed value or value if no value transformer is specified.\n * @public\n * @memberof Option#\n */\n transform: function(value) {\n var transformer = this._valueTransformer;\n if (typeof transformer === 'function') {\n return transformer(value, this);\n }\n\n return value;\n }\n\n});\n\nmodule.exports = Option;\n\n/**\n * Returns a transformed value for the specified value to be applied for the option provided.\n *\n * @callback Option~ValueTransformer\n * @param {*} value - the value to be transformed\n * @param {Option} option - the {@link Option} for which value is being transformed\n * @return {*} The transform value.\n */\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Contains utility methods that are useful throughout the library.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar Utilities = Nevis.extend(null, {\n\n /**\n * Returns the absolute value of a given number.\n *\n * This method is simply a convenient shorthand for Math.abs while ensuring that nulls are returned as\n * null instead of zero.\n *\n * @param {number} value - the number whose absolute value is to be returned\n * @return {number} The absolute value of value or null if value is\n * null.\n * @public\n * @static\n * @memberof Utilities\n */\n abs: function(value) {\n return value != null ? Math.abs(value) : null;\n },\n\n /**\n * Returns whether the specified object has a property with the specified name as an own\n * (not inherited) property.\n *\n * @param {Object} object - the object on which the property is to be checked\n * @param {string} name - the name of the property to be checked\n * @return {boolean} true if object has an own property with name.\n * @public\n * @static\n * @memberof Utilities\n */\n hasOwn: function(object, name) {\n return Object.prototype.hasOwnProperty.call(object, name);\n },\n\n /**\n * A non-operation method that does absolutely nothing.\n *\n * @return {void}\n * @public\n * @static\n * @memberof Utilities\n */\n noop: function() {},\n\n /**\n * Transforms the specified string to upper case while remaining null-safe.\n *\n * @param {string} string - the string to be transformed to upper case\n * @return {string} string transformed to upper case if string is not null.\n * @public\n * @static\n * @memberof Utilities\n */\n toUpperCase: function(string) {\n return string != null ? string.toUpperCase() : null;\n }\n\n});\n\nmodule.exports = Utilities;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\nvar Utilities = require('../util/Utilities');\n\n/**\n * Manages multiple {@link Option} instances that are intended to be used by multiple implementations.\n *\n * Although the option definitions are shared between targets, the values are maintained on the targets themselves.\n *\n * @param {Option[]} options - the options to be used\n * @public\n * @class\n * @extends Nevis\n */\nvar OptionManager = Nevis.extend(function(options) {\n /**\n * The available options for this {@link OptionManager}.\n *\n * @public\n * @type {Object.}\n * @memberof OptionManager#\n */\n this.options = {};\n\n options.forEach(function(option) {\n this.options[option.name] = option;\n }, this);\n}, {\n\n /**\n * Returns whether an option with the specified name is available.\n *\n * @param {string} name - the name of the {@link Option} whose existence is to be checked\n * @return {boolean} true if an {@link Option} exists with name; otherwise\n * false.\n * @public\n * @memberof OptionManager#\n */\n exists: function(name) {\n return this.options[name] != null;\n },\n\n /**\n * Returns the value of the option with the specified name on the target object provided.\n *\n * @param {string} name - the name of the {@link Option} whose value on target is to be returned\n * @param {Object} target - the object from which the value of the named {@link Option} is to be returned\n * @return {*} The value of the {@link Option} with name on target.\n * @public\n * @memberof OptionManager#\n */\n get: function(name, target) {\n return OptionManager._get(this.options[name], target);\n },\n\n /**\n * Returns a copy of all of the available options on the target object provided.\n *\n * @param {Object} target - the object from which the option name/value pairs are to be returned\n * @return {Object.} A hash containing the name/value pairs of all options on target.\n * @public\n * @memberof OptionManager#\n */\n getAll: function(target) {\n var name;\n var options = this.options;\n var result = {};\n\n for (name in options) {\n if (Utilities.hasOwn(options, name)) {\n result[name] = OptionManager._get(options[name], target);\n }\n }\n\n return result;\n },\n\n /**\n * Initializes the available options for the target object provided and then applies the initial values\n * within the speciifed options.\n *\n * This method will throw an error if any of the names within options does not match an available option.\n *\n * This involves setting the default values and defining properties for all of the available options on\n * target before finally calling {@link OptionMananger#setAll} with options and\n * target. Any options that are configured to be modifiable will have a setter included in their defined\n * property that will allow its corresponding value to be modified.\n *\n * If a change handler is specified, it will be called whenever the value changes on target for a\n * modifiable option, but only when done so via the defined property's setter.\n *\n * @param {Object.} options - the name/value pairs of the initial options to be set\n * @param {Object} target - the object on which the options are to be initialized\n * @param {Function} [changeHandler] - the function to be called whenever the value of an modifiable option changes on\n * target\n * @return {void}\n * @throws {Error} If options contains an invalid option name.\n * @public\n * @memberof OptionManager#\n */\n init: function(options, target, changeHandler) {\n if (typeof changeHandler !== 'function') {\n changeHandler = Utilities.noop;\n }\n\n var name, option;\n\n for (name in this.options) {\n if (Utilities.hasOwn(this.options, name)) {\n option = this.options[name];\n\n OptionManager._set(option, option.defaultValue, target);\n OptionManager._createAccessor(option, target, changeHandler);\n }\n }\n\n this._setAll(options, target, true);\n },\n\n /**\n * Sets the value of the option with the specified name on the target object provided to\n * value.\n *\n * This method will throw an error if name does not match an available option or matches an option that\n * cannot be modified.\n *\n * If value is null and the {@link Option} has a default value configured, then that default\n * value will be used instead. If the {@link Option} also has a value transformer configured, it will be used to\n * transform whichever value was determined to be used.\n *\n * This method returns whether the value of the underlying field on target was changed as a result.\n *\n * @param {string} name - the name of the {@link Option} whose value is to be set\n * @param {*} value - the value to be set for the named {@link Option} on target\n * @param {Object} target - the object on which value is to be set for the named {@link Option}\n * @return {boolean} true if the underlying field on target was changed; otherwise\n * false.\n * @throws {Error} If name is invalid or is for an option that cannot be modified.\n * @public\n * @memberof OptionManager#\n */\n set: function(name, value, target) {\n return this._set(name, value, target);\n },\n\n /**\n * Sets all of the specified options on the target object provided to their corresponding\n * values.\n *\n * This method will throw an error if any of the names within options does not match an available option\n * or matches an option that cannot be modified.\n *\n * If any value within options is null and the corresponding {@link Option} has a default\n * value configured, then that default value will be used instead. If an {@link Option} also has a value transformer\n * configured, it will be used to transform whichever value was determined to be used.\n *\n * This method returns whether the value for any of the underlying fields on target were changed as a\n * result.\n *\n * @param {Object.} options - the name/value pairs of options to be set\n * @param {Object} target - the object on which the options are to be set\n * @return {boolean} true if any of the underlying fields on target were changed; otherwise\n * false.\n * @throws {Error} If options contains an invalid option name or an option that cannot be modiifed.\n * @public\n * @memberof OptionManager#\n */\n setAll: function(options, target) {\n return this._setAll(options, target);\n },\n\n _set: function(name, value, target, allowUnmodifiable) {\n var option = this.options[name];\n if (!option) {\n throw new Error('Invalid option: ' + name);\n }\n if (!option.modifiable && !allowUnmodifiable) {\n throw new Error('Option cannot be modified: ' + name);\n }\n\n return OptionManager._set(option, value, target);\n },\n\n _setAll: function(options, target, allowUnmodifiable) {\n if (!options) {\n return false;\n }\n\n var name;\n var changed = false;\n\n for (name in options) {\n if (Utilities.hasOwn(options, name) && this._set(name, options[name], target, allowUnmodifiable)) {\n changed = true;\n }\n }\n\n return changed;\n }\n\n}, {\n\n _createAccessor: function(option, target, changeHandler) {\n var descriptor = {\n get: function() {\n return OptionManager._get(option, target);\n }\n };\n\n if (option.modifiable) {\n descriptor.set = function(value) {\n if (OptionManager._set(option, value, target)) {\n changeHandler(value, option);\n }\n };\n }\n\n Object.defineProperty(target, option.name, descriptor);\n },\n\n _get: function(option, target) {\n return target['_' + option.name];\n },\n\n _set: function(option, value, target) {\n var fieldName = '_' + option.name;\n var oldValue = target[fieldName];\n var newValue = option.transform(value != null ? value : option.defaultValue);\n\n target[fieldName] = newValue;\n\n return newValue !== oldValue;\n }\n\n});\n\nmodule.exports = OptionManager;\n\n/**\n * Called whenever the value of a modifiable {@link Option} is changed on a target object via the defined property's\n * setter.\n *\n * @callback OptionManager~ChangeHandler\n * @param {*} value - the new value for option on the target object\n * @param {Option} option - the modifable {@link Option} whose value has changed on the target object.\n * @return {void}\n */\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * A basic manager for {@link Service} implementations that are mapped to simple names.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar ServiceManager = Nevis.extend(function() {\n this._services = {};\n}, {\n\n /**\n * Returns the {@link Service} being managed with the specified name.\n *\n * @param {string} name - the name of the {@link Service} to be returned\n * @return {Service} The {@link Service} is being managed with name.\n * @throws {Error} If no {@link Service} is being managed with name.\n * @public\n * @memberof ServiceManager#\n */\n getService: function(name) {\n var service = this._services[name];\n if (!service) {\n throw new Error('Service is not being managed with name: ' + name);\n }\n\n return service;\n },\n\n /**\n * Sets the {@link Service} implementation to be managed for the specified name to the\n * service provided.\n *\n * @param {string} name - the name of the {@link Service} to be managed with name\n * @param {Service} service - the {@link Service} implementation to be managed\n * @return {void}\n * @throws {Error} If a {@link Service} is already being managed with the same name.\n * @public\n * @memberof ServiceManager#\n */\n setService: function(name, service) {\n if (this._services[name]) {\n throw new Error('Service is already managed with name: ' + name);\n }\n\n if (service) {\n this._services[name] = service;\n }\n }\n\n});\n\nmodule.exports = ServiceManager;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\nvar CanvasRenderer = require('./renderer/CanvasRenderer');\nvar Frame = require('./Frame');\nvar ImageRenderer = require('./renderer/ImageRenderer');\nvar Option = require('./option/Option');\nvar OptionManager = require('./option/OptionManager');\nvar ServiceManager = require('./service/ServiceManager');\nvar Utilities = require('./util/Utilities');\n\nvar optionManager = new OptionManager([\n new Option('background', true, 'white'),\n new Option('backgroundAlpha', true, 1, Utilities.abs),\n new Option('element'),\n new Option('foreground', true, 'black'),\n new Option('foregroundAlpha', true, 1, Utilities.abs),\n new Option('level', true, 'L', Utilities.toUpperCase),\n new Option('mime', true, 'image/png'),\n new Option('padding', true, null, Utilities.abs),\n new Option('size', true, 100, Utilities.abs),\n new Option('value', true, '')\n]);\nvar serviceManager = new ServiceManager();\n\n/**\n * Enables configuration of a QR code generator which uses HTML5 canvas for rendering.\n *\n * @param {QRious~Options} [options] - the options to be used\n * @throws {Error} If any options are invalid.\n * @public\n * @class\n * @extends Nevis\n */\nvar QRious = Nevis.extend(function(options) {\n optionManager.init(options, this, this.update.bind(this));\n\n var element = optionManager.get('element', this);\n var elementService = serviceManager.getService('element');\n var canvas = element && elementService.isCanvas(element) ? element : elementService.createCanvas();\n var image = element && elementService.isImage(element) ? element : elementService.createImage();\n\n this._canvasRenderer = new CanvasRenderer(this, canvas, true);\n this._imageRenderer = new ImageRenderer(this, image, image === element);\n\n this.update();\n}, {\n\n /**\n * Returns all of the options configured for this {@link QRious}.\n *\n * Any changes made to the returned object will not be reflected in the options themselves or their corresponding\n * underlying fields.\n *\n * @return {Object.} A copy of the applied options.\n * @public\n * @memberof QRious#\n */\n get: function() {\n return optionManager.getAll(this);\n },\n\n /**\n * Sets all of the specified options and automatically updates this {@link QRious} if any of the\n * underlying fields are changed as a result.\n *\n * This is the preferred method for updating multiple options at one time to avoid unnecessary updates between\n * changes.\n *\n * @param {QRious~Options} options - the options to be set\n * @return {void}\n * @throws {Error} If any options are invalid or cannot be modified.\n * @public\n * @memberof QRious#\n */\n set: function(options) {\n if (optionManager.setAll(options, this)) {\n this.update();\n }\n },\n\n /**\n * Returns the image data URI for the generated QR code using the mime provided.\n *\n * @param {string} [mime] - the MIME type for the image\n * @return {string} The image data URI for the QR code.\n * @public\n * @memberof QRious#\n */\n toDataURL: function(mime) {\n return this.canvas.toDataURL(mime || this.mime);\n },\n\n /**\n * Updates this {@link QRious} by generating a new {@link Frame} and re-rendering the QR code.\n *\n * @return {void}\n * @protected\n * @memberof QRious#\n */\n update: function() {\n var frame = new Frame({\n level: this.level,\n value: this.value\n });\n\n this._canvasRenderer.render(frame);\n this._imageRenderer.render(frame);\n }\n\n}, {\n\n /**\n * Configures the service provided to be used by all {@link QRious} instances.\n *\n * @param {Service} service - the {@link Service} to be configured\n * @return {void}\n * @throws {Error} If a {@link Service} has already been configured with the same name.\n * @public\n * @static\n * @memberof QRious\n */\n use: function(service) {\n serviceManager.setService(service.getName(), service);\n }\n\n});\n\nObject.defineProperties(QRious.prototype, {\n\n canvas: {\n /**\n * Returns the canvas element being used to render the QR code for this {@link QRious}.\n *\n * @return {*} The canvas element.\n * @public\n * @memberof QRious#\n * @alias canvas\n */\n get: function() {\n return this._canvasRenderer.getElement();\n }\n },\n\n image: {\n /**\n * Returns the img element being used to render the QR code for this {@link QRious}.\n *\n * @return {*} The img element.\n * @public\n * @memberof QRious#\n * @alias image\n */\n get: function() {\n return this._imageRenderer.getElement();\n }\n }\n\n});\n\nmodule.exports = QRious;\n\n/**\n * The options used by {@link QRious}.\n *\n * @typedef {Object} QRious~Options\n * @property {string} [background=\"white\"] - The background color to be applied to the QR code.\n * @property {number} [backgroundAlpha=1] - The background alpha to be applied to the QR code.\n * @property {*} [element] - The element to be used to render the QR code which may either be an canvas or\n * img. The element(s) will be created if needed.\n * @property {string} [foreground=\"black\"] - The foreground color to be applied to the QR code.\n * @property {number} [foregroundAlpha=1] - The foreground alpha to be applied to the QR code.\n * @property {string} [level=\"L\"] - The error correction level to be applied to the QR code.\n * @property {string} [mime=\"image/png\"] - The MIME type to be used to render the image for the QR code.\n * @property {number} [padding] - The padding for the QR code in pixels.\n * @property {number} [size=100] - The size of the QR code in pixels.\n * @property {string} [value=\"\"] - The value to be encoded within the QR code.\n */\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nmodule.exports = require('./src/QRious');\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Nevis = require('nevis/lite');\n\n/**\n * Defines a service contract that must be met by all implementations.\n *\n * @public\n * @class\n * @extends Nevis\n */\nvar Service = Nevis.extend({\n\n /**\n * Returns the name of this {@link Service}.\n *\n * @return {string} The service name.\n * @public\n * @abstract\n * @memberof Service#\n */\n getName: function() {}\n\n});\n\nmodule.exports = Service;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar Service = require('../Service');\n\n/**\n * A service for working with elements.\n *\n * @public\n * @class\n * @extends Service\n */\nvar ElementService = Service.extend({\n\n /**\n * Creates an instance of a canvas element.\n *\n * Implementations of {@link ElementService} must override this method with their own specific logic.\n *\n * @return {*} The newly created canvas element.\n * @public\n * @abstract\n * @memberof ElementService#\n */\n createCanvas: function() {},\n\n /**\n * Creates an instance of a image element.\n *\n * Implementations of {@link ElementService} must override this method with their own specific logic.\n *\n * @return {*} The newly created image element.\n * @public\n * @abstract\n * @memberof ElementService#\n */\n createImage: function() {},\n\n /**\n * @override\n */\n getName: function() {\n return 'element';\n },\n\n /**\n * Returns whether the specified element is a canvas.\n *\n * Implementations of {@link ElementService} must override this method with their own specific logic.\n *\n * @param {*} element - the element to be checked\n * @return {boolean} true if element is a canvas; otherwise false.\n * @public\n * @abstract\n * @memberof ElementService#\n */\n isCanvas: function(element) {},\n\n /**\n * Returns whether the specified element is an image.\n *\n * Implementations of {@link ElementService} must override this method with their own specific logic.\n *\n * @param {*} element - the element to be checked\n * @return {boolean} true if element is an image; otherwise false.\n * @public\n * @abstract\n * @memberof ElementService#\n */\n isImage: function(element) {}\n\n});\n\nmodule.exports = ElementService;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar ElementService = require('qrious-core/src/service/element/ElementService');\n\n/**\n * An implementation of {@link ElementService} intended for use within a browser environment.\n *\n * @public\n * @class\n * @extends ElementService\n */\nvar BrowserElementService = ElementService.extend({\n\n /**\n * @override\n */\n createCanvas: function() {\n return document.createElement('canvas');\n },\n\n /**\n * @override\n */\n createImage: function() {\n return document.createElement('img');\n },\n\n /**\n * @override\n */\n isCanvas: function(element) {\n return element instanceof HTMLCanvasElement;\n },\n\n /**\n * @override\n */\n isImage: function(element) {\n return element instanceof HTMLImageElement;\n }\n\n});\n\nmodule.exports = BrowserElementService;\n", "/*\n * QRious\n * Copyright (C) 2017 Alasdair Mercer\n * Copyright (C) 2010 Tom Zerucha\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n */\n\n'use strict';\n\nvar QRious = require('qrious-core');\n\nvar BrowserElementService = require('./service/element/BrowserElementService');\n\nQRious.use(new BrowserElementService());\n\nmodule.exports = QRious;\n", "/*\nTurbo 7.3.0\nCopyright \u00A9 2023 37signals LLC\n */\n(function () {\n if (window.Reflect === undefined ||\n window.customElements === undefined ||\n window.customElements.polyfillWrapFlushCallback) {\n return;\n }\n const BuiltInHTMLElement = HTMLElement;\n const wrapperForTheName = {\n HTMLElement: function HTMLElement() {\n return Reflect.construct(BuiltInHTMLElement, [], this.constructor);\n },\n };\n window.HTMLElement = wrapperForTheName[\"HTMLElement\"];\n HTMLElement.prototype = BuiltInHTMLElement.prototype;\n HTMLElement.prototype.constructor = HTMLElement;\n Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);\n})();\n\n/**\n * The MIT License (MIT)\n * \n * Copyright (c) 2019 Javan Makhmali\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n(function(prototype) {\n if (typeof prototype.requestSubmit == \"function\") return\n\n prototype.requestSubmit = function(submitter) {\n if (submitter) {\n validateSubmitter(submitter, this);\n submitter.click();\n } else {\n submitter = document.createElement(\"input\");\n submitter.type = \"submit\";\n submitter.hidden = true;\n this.appendChild(submitter);\n submitter.click();\n this.removeChild(submitter);\n }\n };\n\n function validateSubmitter(submitter, form) {\n submitter instanceof HTMLElement || raise(TypeError, \"parameter 1 is not of type 'HTMLElement'\");\n submitter.type == \"submit\" || raise(TypeError, \"The specified element is not a submit button\");\n submitter.form == form || raise(DOMException, \"The specified element is not owned by this form element\", \"NotFoundError\");\n }\n\n function raise(errorConstructor, message, name) {\n throw new errorConstructor(\"Failed to execute 'requestSubmit' on 'HTMLFormElement': \" + message + \".\", name)\n }\n})(HTMLFormElement.prototype);\n\nconst submittersByForm = new WeakMap();\nfunction findSubmitterFromClickTarget(target) {\n const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;\n const candidate = element ? element.closest(\"input, button\") : null;\n return (candidate === null || candidate === void 0 ? void 0 : candidate.type) == \"submit\" ? candidate : null;\n}\nfunction clickCaptured(event) {\n const submitter = findSubmitterFromClickTarget(event.target);\n if (submitter && submitter.form) {\n submittersByForm.set(submitter.form, submitter);\n }\n}\n(function () {\n if (\"submitter\" in Event.prototype)\n return;\n let prototype = window.Event.prototype;\n if (\"SubmitEvent\" in window && /Apple Computer/.test(navigator.vendor)) {\n prototype = window.SubmitEvent.prototype;\n }\n else if (\"SubmitEvent\" in window) {\n return;\n }\n addEventListener(\"click\", clickCaptured, true);\n Object.defineProperty(prototype, \"submitter\", {\n get() {\n if (this.type == \"submit\" && this.target instanceof HTMLFormElement) {\n return submittersByForm.get(this.target);\n }\n },\n });\n})();\n\nvar FrameLoadingStyle;\n(function (FrameLoadingStyle) {\n FrameLoadingStyle[\"eager\"] = \"eager\";\n FrameLoadingStyle[\"lazy\"] = \"lazy\";\n})(FrameLoadingStyle || (FrameLoadingStyle = {}));\nclass FrameElement extends HTMLElement {\n static get observedAttributes() {\n return [\"disabled\", \"complete\", \"loading\", \"src\"];\n }\n constructor() {\n super();\n this.loaded = Promise.resolve();\n this.delegate = new FrameElement.delegateConstructor(this);\n }\n connectedCallback() {\n this.delegate.connect();\n }\n disconnectedCallback() {\n this.delegate.disconnect();\n }\n reload() {\n return this.delegate.sourceURLReloaded();\n }\n attributeChangedCallback(name) {\n if (name == \"loading\") {\n this.delegate.loadingStyleChanged();\n }\n else if (name == \"complete\") {\n this.delegate.completeChanged();\n }\n else if (name == \"src\") {\n this.delegate.sourceURLChanged();\n }\n else {\n this.delegate.disabledChanged();\n }\n }\n get src() {\n return this.getAttribute(\"src\");\n }\n set src(value) {\n if (value) {\n this.setAttribute(\"src\", value);\n }\n else {\n this.removeAttribute(\"src\");\n }\n }\n get loading() {\n return frameLoadingStyleFromString(this.getAttribute(\"loading\") || \"\");\n }\n set loading(value) {\n if (value) {\n this.setAttribute(\"loading\", value);\n }\n else {\n this.removeAttribute(\"loading\");\n }\n }\n get disabled() {\n return this.hasAttribute(\"disabled\");\n }\n set disabled(value) {\n if (value) {\n this.setAttribute(\"disabled\", \"\");\n }\n else {\n this.removeAttribute(\"disabled\");\n }\n }\n get autoscroll() {\n return this.hasAttribute(\"autoscroll\");\n }\n set autoscroll(value) {\n if (value) {\n this.setAttribute(\"autoscroll\", \"\");\n }\n else {\n this.removeAttribute(\"autoscroll\");\n }\n }\n get complete() {\n return !this.delegate.isLoading;\n }\n get isActive() {\n return this.ownerDocument === document && !this.isPreview;\n }\n get isPreview() {\n var _a, _b;\n return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute(\"data-turbo-preview\");\n }\n}\nfunction frameLoadingStyleFromString(style) {\n switch (style.toLowerCase()) {\n case \"lazy\":\n return FrameLoadingStyle.lazy;\n default:\n return FrameLoadingStyle.eager;\n }\n}\n\nfunction expandURL(locatable) {\n return new URL(locatable.toString(), document.baseURI);\n}\nfunction getAnchor(url) {\n let anchorMatch;\n if (url.hash) {\n return url.hash.slice(1);\n }\n else if ((anchorMatch = url.href.match(/#(.*)$/))) {\n return anchorMatch[1];\n }\n}\nfunction getAction(form, submitter) {\n const action = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute(\"formaction\")) || form.getAttribute(\"action\") || form.action;\n return expandURL(action);\n}\nfunction getExtension(url) {\n return (getLastPathComponent(url).match(/\\.[^.]*$/) || [])[0] || \"\";\n}\nfunction isHTML(url) {\n return !!getExtension(url).match(/^(?:|\\.(?:htm|html|xhtml|php))$/);\n}\nfunction isPrefixedBy(baseURL, url) {\n const prefix = getPrefix(url);\n return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);\n}\nfunction locationIsVisitable(location, rootLocation) {\n return isPrefixedBy(location, rootLocation) && isHTML(location);\n}\nfunction getRequestURL(url) {\n const anchor = getAnchor(url);\n return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;\n}\nfunction toCacheKey(url) {\n return getRequestURL(url);\n}\nfunction urlsAreEqual(left, right) {\n return expandURL(left).href == expandURL(right).href;\n}\nfunction getPathComponents(url) {\n return url.pathname.split(\"/\").slice(1);\n}\nfunction getLastPathComponent(url) {\n return getPathComponents(url).slice(-1)[0];\n}\nfunction getPrefix(url) {\n return addTrailingSlash(url.origin + url.pathname);\n}\nfunction addTrailingSlash(value) {\n return value.endsWith(\"/\") ? value : value + \"/\";\n}\n\nclass FetchResponse {\n constructor(response) {\n this.response = response;\n }\n get succeeded() {\n return this.response.ok;\n }\n get failed() {\n return !this.succeeded;\n }\n get clientError() {\n return this.statusCode >= 400 && this.statusCode <= 499;\n }\n get serverError() {\n return this.statusCode >= 500 && this.statusCode <= 599;\n }\n get redirected() {\n return this.response.redirected;\n }\n get location() {\n return expandURL(this.response.url);\n }\n get isHTML() {\n return this.contentType && this.contentType.match(/^(?:text\\/([^\\s;,]+\\b)?html|application\\/xhtml\\+xml)\\b/);\n }\n get statusCode() {\n return this.response.status;\n }\n get contentType() {\n return this.header(\"Content-Type\");\n }\n get responseText() {\n return this.response.clone().text();\n }\n get responseHTML() {\n if (this.isHTML) {\n return this.response.clone().text();\n }\n else {\n return Promise.resolve(undefined);\n }\n }\n header(name) {\n return this.response.headers.get(name);\n }\n}\n\nfunction activateScriptElement(element) {\n if (element.getAttribute(\"data-turbo-eval\") == \"false\") {\n return element;\n }\n else {\n const createdScriptElement = document.createElement(\"script\");\n const cspNonce = getMetaContent(\"csp-nonce\");\n if (cspNonce) {\n createdScriptElement.nonce = cspNonce;\n }\n createdScriptElement.textContent = element.textContent;\n createdScriptElement.async = false;\n copyElementAttributes(createdScriptElement, element);\n return createdScriptElement;\n }\n}\nfunction copyElementAttributes(destinationElement, sourceElement) {\n for (const { name, value } of sourceElement.attributes) {\n destinationElement.setAttribute(name, value);\n }\n}\nfunction createDocumentFragment(html) {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n}\nfunction dispatch(eventName, { target, cancelable, detail } = {}) {\n const event = new CustomEvent(eventName, {\n cancelable,\n bubbles: true,\n composed: true,\n detail,\n });\n if (target && target.isConnected) {\n target.dispatchEvent(event);\n }\n else {\n document.documentElement.dispatchEvent(event);\n }\n return event;\n}\nfunction nextAnimationFrame() {\n return new Promise((resolve) => requestAnimationFrame(() => resolve()));\n}\nfunction nextEventLoopTick() {\n return new Promise((resolve) => setTimeout(() => resolve(), 0));\n}\nfunction nextMicrotask() {\n return Promise.resolve();\n}\nfunction parseHTMLDocument(html = \"\") {\n return new DOMParser().parseFromString(html, \"text/html\");\n}\nfunction unindent(strings, ...values) {\n const lines = interpolate(strings, values).replace(/^\\n/, \"\").split(\"\\n\");\n const match = lines[0].match(/^\\s+/);\n const indent = match ? match[0].length : 0;\n return lines.map((line) => line.slice(indent)).join(\"\\n\");\n}\nfunction interpolate(strings, values) {\n return strings.reduce((result, string, i) => {\n const value = values[i] == undefined ? \"\" : values[i];\n return result + string + value;\n }, \"\");\n}\nfunction uuid() {\n return Array.from({ length: 36 })\n .map((_, i) => {\n if (i == 8 || i == 13 || i == 18 || i == 23) {\n return \"-\";\n }\n else if (i == 14) {\n return \"4\";\n }\n else if (i == 19) {\n return (Math.floor(Math.random() * 4) + 8).toString(16);\n }\n else {\n return Math.floor(Math.random() * 15).toString(16);\n }\n })\n .join(\"\");\n}\nfunction getAttribute(attributeName, ...elements) {\n for (const value of elements.map((element) => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {\n if (typeof value == \"string\")\n return value;\n }\n return null;\n}\nfunction hasAttribute(attributeName, ...elements) {\n return elements.some((element) => element && element.hasAttribute(attributeName));\n}\nfunction markAsBusy(...elements) {\n for (const element of elements) {\n if (element.localName == \"turbo-frame\") {\n element.setAttribute(\"busy\", \"\");\n }\n element.setAttribute(\"aria-busy\", \"true\");\n }\n}\nfunction clearBusyState(...elements) {\n for (const element of elements) {\n if (element.localName == \"turbo-frame\") {\n element.removeAttribute(\"busy\");\n }\n element.removeAttribute(\"aria-busy\");\n }\n}\nfunction waitForLoad(element, timeoutInMilliseconds = 2000) {\n return new Promise((resolve) => {\n const onComplete = () => {\n element.removeEventListener(\"error\", onComplete);\n element.removeEventListener(\"load\", onComplete);\n resolve();\n };\n element.addEventListener(\"load\", onComplete, { once: true });\n element.addEventListener(\"error\", onComplete, { once: true });\n setTimeout(resolve, timeoutInMilliseconds);\n });\n}\nfunction getHistoryMethodForAction(action) {\n switch (action) {\n case \"replace\":\n return history.replaceState;\n case \"advance\":\n case \"restore\":\n return history.pushState;\n }\n}\nfunction isAction(action) {\n return action == \"advance\" || action == \"replace\" || action == \"restore\";\n}\nfunction getVisitAction(...elements) {\n const action = getAttribute(\"data-turbo-action\", ...elements);\n return isAction(action) ? action : null;\n}\nfunction getMetaElement(name) {\n return document.querySelector(`meta[name=\"${name}\"]`);\n}\nfunction getMetaContent(name) {\n const element = getMetaElement(name);\n return element && element.content;\n}\nfunction setMetaContent(name, content) {\n let element = getMetaElement(name);\n if (!element) {\n element = document.createElement(\"meta\");\n element.setAttribute(\"name\", name);\n document.head.appendChild(element);\n }\n element.setAttribute(\"content\", content);\n return element;\n}\nfunction findClosestRecursively(element, selector) {\n var _a;\n if (element instanceof Element) {\n return (element.closest(selector) ||\n findClosestRecursively(element.assignedSlot || ((_a = element.getRootNode()) === null || _a === void 0 ? void 0 : _a.host), selector));\n }\n}\n\nvar FetchMethod;\n(function (FetchMethod) {\n FetchMethod[FetchMethod[\"get\"] = 0] = \"get\";\n FetchMethod[FetchMethod[\"post\"] = 1] = \"post\";\n FetchMethod[FetchMethod[\"put\"] = 2] = \"put\";\n FetchMethod[FetchMethod[\"patch\"] = 3] = \"patch\";\n FetchMethod[FetchMethod[\"delete\"] = 4] = \"delete\";\n})(FetchMethod || (FetchMethod = {}));\nfunction fetchMethodFromString(method) {\n switch (method.toLowerCase()) {\n case \"get\":\n return FetchMethod.get;\n case \"post\":\n return FetchMethod.post;\n case \"put\":\n return FetchMethod.put;\n case \"patch\":\n return FetchMethod.patch;\n case \"delete\":\n return FetchMethod.delete;\n }\n}\nclass FetchRequest {\n constructor(delegate, method, location, body = new URLSearchParams(), target = null) {\n this.abortController = new AbortController();\n this.resolveRequestPromise = (_value) => { };\n this.delegate = delegate;\n this.method = method;\n this.headers = this.defaultHeaders;\n this.body = body;\n this.url = location;\n this.target = target;\n }\n get location() {\n return this.url;\n }\n get params() {\n return this.url.searchParams;\n }\n get entries() {\n return this.body ? Array.from(this.body.entries()) : [];\n }\n cancel() {\n this.abortController.abort();\n }\n async perform() {\n const { fetchOptions } = this;\n this.delegate.prepareRequest(this);\n await this.allowRequestToBeIntercepted(fetchOptions);\n try {\n this.delegate.requestStarted(this);\n const response = await fetch(this.url.href, fetchOptions);\n return await this.receive(response);\n }\n catch (error) {\n if (error.name !== \"AbortError\") {\n if (this.willDelegateErrorHandling(error)) {\n this.delegate.requestErrored(this, error);\n }\n throw error;\n }\n }\n finally {\n this.delegate.requestFinished(this);\n }\n }\n async receive(response) {\n const fetchResponse = new FetchResponse(response);\n const event = dispatch(\"turbo:before-fetch-response\", {\n cancelable: true,\n detail: { fetchResponse },\n target: this.target,\n });\n if (event.defaultPrevented) {\n this.delegate.requestPreventedHandlingResponse(this, fetchResponse);\n }\n else if (fetchResponse.succeeded) {\n this.delegate.requestSucceededWithResponse(this, fetchResponse);\n }\n else {\n this.delegate.requestFailedWithResponse(this, fetchResponse);\n }\n return fetchResponse;\n }\n get fetchOptions() {\n var _a;\n return {\n method: FetchMethod[this.method].toUpperCase(),\n credentials: \"same-origin\",\n headers: this.headers,\n redirect: \"follow\",\n body: this.isSafe ? null : this.body,\n signal: this.abortSignal,\n referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href,\n };\n }\n get defaultHeaders() {\n return {\n Accept: \"text/html, application/xhtml+xml\",\n };\n }\n get isSafe() {\n return this.method === FetchMethod.get;\n }\n get abortSignal() {\n return this.abortController.signal;\n }\n acceptResponseType(mimeType) {\n this.headers[\"Accept\"] = [mimeType, this.headers[\"Accept\"]].join(\", \");\n }\n async allowRequestToBeIntercepted(fetchOptions) {\n const requestInterception = new Promise((resolve) => (this.resolveRequestPromise = resolve));\n const event = dispatch(\"turbo:before-fetch-request\", {\n cancelable: true,\n detail: {\n fetchOptions,\n url: this.url,\n resume: this.resolveRequestPromise,\n },\n target: this.target,\n });\n if (event.defaultPrevented)\n await requestInterception;\n }\n willDelegateErrorHandling(error) {\n const event = dispatch(\"turbo:fetch-request-error\", {\n target: this.target,\n cancelable: true,\n detail: { request: this, error: error },\n });\n return !event.defaultPrevented;\n }\n}\n\nclass AppearanceObserver {\n constructor(delegate, element) {\n this.started = false;\n this.intersect = (entries) => {\n const lastEntry = entries.slice(-1)[0];\n if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {\n this.delegate.elementAppearedInViewport(this.element);\n }\n };\n this.delegate = delegate;\n this.element = element;\n this.intersectionObserver = new IntersectionObserver(this.intersect);\n }\n start() {\n if (!this.started) {\n this.started = true;\n this.intersectionObserver.observe(this.element);\n }\n }\n stop() {\n if (this.started) {\n this.started = false;\n this.intersectionObserver.unobserve(this.element);\n }\n }\n}\n\nclass StreamMessage {\n static wrap(message) {\n if (typeof message == \"string\") {\n return new this(createDocumentFragment(message));\n }\n else {\n return message;\n }\n }\n constructor(fragment) {\n this.fragment = importStreamElements(fragment);\n }\n}\nStreamMessage.contentType = \"text/vnd.turbo-stream.html\";\nfunction importStreamElements(fragment) {\n for (const element of fragment.querySelectorAll(\"turbo-stream\")) {\n const streamElement = document.importNode(element, true);\n for (const inertScriptElement of streamElement.templateElement.content.querySelectorAll(\"script\")) {\n inertScriptElement.replaceWith(activateScriptElement(inertScriptElement));\n }\n element.replaceWith(streamElement);\n }\n return fragment;\n}\n\nvar FormSubmissionState;\n(function (FormSubmissionState) {\n FormSubmissionState[FormSubmissionState[\"initialized\"] = 0] = \"initialized\";\n FormSubmissionState[FormSubmissionState[\"requesting\"] = 1] = \"requesting\";\n FormSubmissionState[FormSubmissionState[\"waiting\"] = 2] = \"waiting\";\n FormSubmissionState[FormSubmissionState[\"receiving\"] = 3] = \"receiving\";\n FormSubmissionState[FormSubmissionState[\"stopping\"] = 4] = \"stopping\";\n FormSubmissionState[FormSubmissionState[\"stopped\"] = 5] = \"stopped\";\n})(FormSubmissionState || (FormSubmissionState = {}));\nvar FormEnctype;\n(function (FormEnctype) {\n FormEnctype[\"urlEncoded\"] = \"application/x-www-form-urlencoded\";\n FormEnctype[\"multipart\"] = \"multipart/form-data\";\n FormEnctype[\"plain\"] = \"text/plain\";\n})(FormEnctype || (FormEnctype = {}));\nfunction formEnctypeFromString(encoding) {\n switch (encoding.toLowerCase()) {\n case FormEnctype.multipart:\n return FormEnctype.multipart;\n case FormEnctype.plain:\n return FormEnctype.plain;\n default:\n return FormEnctype.urlEncoded;\n }\n}\nclass FormSubmission {\n static confirmMethod(message, _element, _submitter) {\n return Promise.resolve(confirm(message));\n }\n constructor(delegate, formElement, submitter, mustRedirect = false) {\n this.state = FormSubmissionState.initialized;\n this.delegate = delegate;\n this.formElement = formElement;\n this.submitter = submitter;\n this.formData = buildFormData(formElement, submitter);\n this.location = expandURL(this.action);\n if (this.method == FetchMethod.get) {\n mergeFormDataEntries(this.location, [...this.body.entries()]);\n }\n this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);\n this.mustRedirect = mustRedirect;\n }\n get method() {\n var _a;\n const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute(\"formmethod\")) || this.formElement.getAttribute(\"method\") || \"\";\n return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;\n }\n get action() {\n var _a;\n const formElementAction = typeof this.formElement.action === \"string\" ? this.formElement.action : null;\n if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute(\"formaction\")) {\n return this.submitter.getAttribute(\"formaction\") || \"\";\n }\n else {\n return this.formElement.getAttribute(\"action\") || formElementAction || \"\";\n }\n }\n get body() {\n if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {\n return new URLSearchParams(this.stringFormData);\n }\n else {\n return this.formData;\n }\n }\n get enctype() {\n var _a;\n return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute(\"formenctype\")) || this.formElement.enctype);\n }\n get isSafe() {\n return this.fetchRequest.isSafe;\n }\n get stringFormData() {\n return [...this.formData].reduce((entries, [name, value]) => {\n return entries.concat(typeof value == \"string\" ? [[name, value]] : []);\n }, []);\n }\n async start() {\n const { initialized, requesting } = FormSubmissionState;\n const confirmationMessage = getAttribute(\"data-turbo-confirm\", this.submitter, this.formElement);\n if (typeof confirmationMessage === \"string\") {\n const answer = await FormSubmission.confirmMethod(confirmationMessage, this.formElement, this.submitter);\n if (!answer) {\n return;\n }\n }\n if (this.state == initialized) {\n this.state = requesting;\n return this.fetchRequest.perform();\n }\n }\n stop() {\n const { stopping, stopped } = FormSubmissionState;\n if (this.state != stopping && this.state != stopped) {\n this.state = stopping;\n this.fetchRequest.cancel();\n return true;\n }\n }\n prepareRequest(request) {\n if (!request.isSafe) {\n const token = getCookieValue(getMetaContent(\"csrf-param\")) || getMetaContent(\"csrf-token\");\n if (token) {\n request.headers[\"X-CSRF-Token\"] = token;\n }\n }\n if (this.requestAcceptsTurboStreamResponse(request)) {\n request.acceptResponseType(StreamMessage.contentType);\n }\n }\n requestStarted(_request) {\n var _a;\n this.state = FormSubmissionState.waiting;\n (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute(\"disabled\", \"\");\n this.setSubmitsWith();\n dispatch(\"turbo:submit-start\", {\n target: this.formElement,\n detail: { formSubmission: this },\n });\n this.delegate.formSubmissionStarted(this);\n }\n requestPreventedHandlingResponse(request, response) {\n this.result = { success: response.succeeded, fetchResponse: response };\n }\n requestSucceededWithResponse(request, response) {\n if (response.clientError || response.serverError) {\n this.delegate.formSubmissionFailedWithResponse(this, response);\n }\n else if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {\n const error = new Error(\"Form responses must redirect to another location\");\n this.delegate.formSubmissionErrored(this, error);\n }\n else {\n this.state = FormSubmissionState.receiving;\n this.result = { success: true, fetchResponse: response };\n this.delegate.formSubmissionSucceededWithResponse(this, response);\n }\n }\n requestFailedWithResponse(request, response) {\n this.result = { success: false, fetchResponse: response };\n this.delegate.formSubmissionFailedWithResponse(this, response);\n }\n requestErrored(request, error) {\n this.result = { success: false, error };\n this.delegate.formSubmissionErrored(this, error);\n }\n requestFinished(_request) {\n var _a;\n this.state = FormSubmissionState.stopped;\n (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute(\"disabled\");\n this.resetSubmitterText();\n dispatch(\"turbo:submit-end\", {\n target: this.formElement,\n detail: Object.assign({ formSubmission: this }, this.result),\n });\n this.delegate.formSubmissionFinished(this);\n }\n setSubmitsWith() {\n if (!this.submitter || !this.submitsWith)\n return;\n if (this.submitter.matches(\"button\")) {\n this.originalSubmitText = this.submitter.innerHTML;\n this.submitter.innerHTML = this.submitsWith;\n }\n else if (this.submitter.matches(\"input\")) {\n const input = this.submitter;\n this.originalSubmitText = input.value;\n input.value = this.submitsWith;\n }\n }\n resetSubmitterText() {\n if (!this.submitter || !this.originalSubmitText)\n return;\n if (this.submitter.matches(\"button\")) {\n this.submitter.innerHTML = this.originalSubmitText;\n }\n else if (this.submitter.matches(\"input\")) {\n const input = this.submitter;\n input.value = this.originalSubmitText;\n }\n }\n requestMustRedirect(request) {\n return !request.isSafe && this.mustRedirect;\n }\n requestAcceptsTurboStreamResponse(request) {\n return !request.isSafe || hasAttribute(\"data-turbo-stream\", this.submitter, this.formElement);\n }\n get submitsWith() {\n var _a;\n return (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute(\"data-turbo-submits-with\");\n }\n}\nfunction buildFormData(formElement, submitter) {\n const formData = new FormData(formElement);\n const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute(\"name\");\n const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute(\"value\");\n if (name) {\n formData.append(name, value || \"\");\n }\n return formData;\n}\nfunction getCookieValue(cookieName) {\n if (cookieName != null) {\n const cookies = document.cookie ? document.cookie.split(\"; \") : [];\n const cookie = cookies.find((cookie) => cookie.startsWith(cookieName));\n if (cookie) {\n const value = cookie.split(\"=\").slice(1).join(\"=\");\n return value ? decodeURIComponent(value) : undefined;\n }\n }\n}\nfunction responseSucceededWithoutRedirect(response) {\n return response.statusCode == 200 && !response.redirected;\n}\nfunction mergeFormDataEntries(url, entries) {\n const searchParams = new URLSearchParams();\n for (const [name, value] of entries) {\n if (value instanceof File)\n continue;\n searchParams.append(name, value);\n }\n url.search = searchParams.toString();\n return url;\n}\n\nclass Snapshot {\n constructor(element) {\n this.element = element;\n }\n get activeElement() {\n return this.element.ownerDocument.activeElement;\n }\n get children() {\n return [...this.element.children];\n }\n hasAnchor(anchor) {\n return this.getElementForAnchor(anchor) != null;\n }\n getElementForAnchor(anchor) {\n return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null;\n }\n get isConnected() {\n return this.element.isConnected;\n }\n get firstAutofocusableElement() {\n const inertDisabledOrHidden = \"[inert], :disabled, [hidden], details:not([open]), dialog:not([open])\";\n for (const element of this.element.querySelectorAll(\"[autofocus]\")) {\n if (element.closest(inertDisabledOrHidden) == null)\n return element;\n else\n continue;\n }\n return null;\n }\n get permanentElements() {\n return queryPermanentElementsAll(this.element);\n }\n getPermanentElementById(id) {\n return getPermanentElementById(this.element, id);\n }\n getPermanentElementMapForSnapshot(snapshot) {\n const permanentElementMap = {};\n for (const currentPermanentElement of this.permanentElements) {\n const { id } = currentPermanentElement;\n const newPermanentElement = snapshot.getPermanentElementById(id);\n if (newPermanentElement) {\n permanentElementMap[id] = [currentPermanentElement, newPermanentElement];\n }\n }\n return permanentElementMap;\n }\n}\nfunction getPermanentElementById(node, id) {\n return node.querySelector(`#${id}[data-turbo-permanent]`);\n}\nfunction queryPermanentElementsAll(node) {\n return node.querySelectorAll(\"[id][data-turbo-permanent]\");\n}\n\nclass FormSubmitObserver {\n constructor(delegate, eventTarget) {\n this.started = false;\n this.submitCaptured = () => {\n this.eventTarget.removeEventListener(\"submit\", this.submitBubbled, false);\n this.eventTarget.addEventListener(\"submit\", this.submitBubbled, false);\n };\n this.submitBubbled = ((event) => {\n if (!event.defaultPrevented) {\n const form = event.target instanceof HTMLFormElement ? event.target : undefined;\n const submitter = event.submitter || undefined;\n if (form &&\n submissionDoesNotDismissDialog(form, submitter) &&\n submissionDoesNotTargetIFrame(form, submitter) &&\n this.delegate.willSubmitForm(form, submitter)) {\n event.preventDefault();\n event.stopImmediatePropagation();\n this.delegate.formSubmitted(form, submitter);\n }\n }\n });\n this.delegate = delegate;\n this.eventTarget = eventTarget;\n }\n start() {\n if (!this.started) {\n this.eventTarget.addEventListener(\"submit\", this.submitCaptured, true);\n this.started = true;\n }\n }\n stop() {\n if (this.started) {\n this.eventTarget.removeEventListener(\"submit\", this.submitCaptured, true);\n this.started = false;\n }\n }\n}\nfunction submissionDoesNotDismissDialog(form, submitter) {\n const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute(\"formmethod\")) || form.getAttribute(\"method\");\n return method != \"dialog\";\n}\nfunction submissionDoesNotTargetIFrame(form, submitter) {\n if ((submitter === null || submitter === void 0 ? void 0 : submitter.hasAttribute(\"formtarget\")) || form.hasAttribute(\"target\")) {\n const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute(\"formtarget\")) || form.target;\n for (const element of document.getElementsByName(target)) {\n if (element instanceof HTMLIFrameElement)\n return false;\n }\n return true;\n }\n else {\n return true;\n }\n}\n\nclass View {\n constructor(delegate, element) {\n this.resolveRenderPromise = (_value) => { };\n this.resolveInterceptionPromise = (_value) => { };\n this.delegate = delegate;\n this.element = element;\n }\n scrollToAnchor(anchor) {\n const element = this.snapshot.getElementForAnchor(anchor);\n if (element) {\n this.scrollToElement(element);\n this.focusElement(element);\n }\n else {\n this.scrollToPosition({ x: 0, y: 0 });\n }\n }\n scrollToAnchorFromLocation(location) {\n this.scrollToAnchor(getAnchor(location));\n }\n scrollToElement(element) {\n element.scrollIntoView();\n }\n focusElement(element) {\n if (element instanceof HTMLElement) {\n if (element.hasAttribute(\"tabindex\")) {\n element.focus();\n }\n else {\n element.setAttribute(\"tabindex\", \"-1\");\n element.focus();\n element.removeAttribute(\"tabindex\");\n }\n }\n }\n scrollToPosition({ x, y }) {\n this.scrollRoot.scrollTo(x, y);\n }\n scrollToTop() {\n this.scrollToPosition({ x: 0, y: 0 });\n }\n get scrollRoot() {\n return window;\n }\n async render(renderer) {\n const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;\n if (shouldRender) {\n try {\n this.renderPromise = new Promise((resolve) => (this.resolveRenderPromise = resolve));\n this.renderer = renderer;\n await this.prepareToRenderSnapshot(renderer);\n const renderInterception = new Promise((resolve) => (this.resolveInterceptionPromise = resolve));\n const options = { resume: this.resolveInterceptionPromise, render: this.renderer.renderElement };\n const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);\n if (!immediateRender)\n await renderInterception;\n await this.renderSnapshot(renderer);\n this.delegate.viewRenderedSnapshot(snapshot, isPreview);\n this.delegate.preloadOnLoadLinksForView(this.element);\n this.finishRenderingSnapshot(renderer);\n }\n finally {\n delete this.renderer;\n this.resolveRenderPromise(undefined);\n delete this.renderPromise;\n }\n }\n else {\n this.invalidate(renderer.reloadReason);\n }\n }\n invalidate(reason) {\n this.delegate.viewInvalidated(reason);\n }\n async prepareToRenderSnapshot(renderer) {\n this.markAsPreview(renderer.isPreview);\n await renderer.prepareToRender();\n }\n markAsPreview(isPreview) {\n if (isPreview) {\n this.element.setAttribute(\"data-turbo-preview\", \"\");\n }\n else {\n this.element.removeAttribute(\"data-turbo-preview\");\n }\n }\n async renderSnapshot(renderer) {\n await renderer.render();\n }\n finishRenderingSnapshot(renderer) {\n renderer.finishRendering();\n }\n}\n\nclass FrameView extends View {\n missing() {\n this.element.innerHTML = `Content missing`;\n }\n get snapshot() {\n return new Snapshot(this.element);\n }\n}\n\nclass LinkInterceptor {\n constructor(delegate, element) {\n this.clickBubbled = (event) => {\n if (this.respondsToEventTarget(event.target)) {\n this.clickEvent = event;\n }\n else {\n delete this.clickEvent;\n }\n };\n this.linkClicked = ((event) => {\n if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {\n if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {\n this.clickEvent.preventDefault();\n event.preventDefault();\n this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);\n }\n }\n delete this.clickEvent;\n });\n this.willVisit = ((_event) => {\n delete this.clickEvent;\n });\n this.delegate = delegate;\n this.element = element;\n }\n start() {\n this.element.addEventListener(\"click\", this.clickBubbled);\n document.addEventListener(\"turbo:click\", this.linkClicked);\n document.addEventListener(\"turbo:before-visit\", this.willVisit);\n }\n stop() {\n this.element.removeEventListener(\"click\", this.clickBubbled);\n document.removeEventListener(\"turbo:click\", this.linkClicked);\n document.removeEventListener(\"turbo:before-visit\", this.willVisit);\n }\n respondsToEventTarget(target) {\n const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;\n return element && element.closest(\"turbo-frame, html\") == this.element;\n }\n}\n\nclass LinkClickObserver {\n constructor(delegate, eventTarget) {\n this.started = false;\n this.clickCaptured = () => {\n this.eventTarget.removeEventListener(\"click\", this.clickBubbled, false);\n this.eventTarget.addEventListener(\"click\", this.clickBubbled, false);\n };\n this.clickBubbled = (event) => {\n if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {\n const target = (event.composedPath && event.composedPath()[0]) || event.target;\n const link = this.findLinkFromClickTarget(target);\n if (link && doesNotTargetIFrame(link)) {\n const location = this.getLocationForLink(link);\n if (this.delegate.willFollowLinkToLocation(link, location, event)) {\n event.preventDefault();\n this.delegate.followedLinkToLocation(link, location);\n }\n }\n }\n };\n this.delegate = delegate;\n this.eventTarget = eventTarget;\n }\n start() {\n if (!this.started) {\n this.eventTarget.addEventListener(\"click\", this.clickCaptured, true);\n this.started = true;\n }\n }\n stop() {\n if (this.started) {\n this.eventTarget.removeEventListener(\"click\", this.clickCaptured, true);\n this.started = false;\n }\n }\n clickEventIsSignificant(event) {\n return !((event.target && event.target.isContentEditable) ||\n event.defaultPrevented ||\n event.which > 1 ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n event.shiftKey);\n }\n findLinkFromClickTarget(target) {\n return findClosestRecursively(target, \"a[href]:not([target^=_]):not([download])\");\n }\n getLocationForLink(link) {\n return expandURL(link.getAttribute(\"href\") || \"\");\n }\n}\nfunction doesNotTargetIFrame(anchor) {\n if (anchor.hasAttribute(\"target\")) {\n for (const element of document.getElementsByName(anchor.target)) {\n if (element instanceof HTMLIFrameElement)\n return false;\n }\n return true;\n }\n else {\n return true;\n }\n}\n\nclass FormLinkClickObserver {\n constructor(delegate, element) {\n this.delegate = delegate;\n this.linkInterceptor = new LinkClickObserver(this, element);\n }\n start() {\n this.linkInterceptor.start();\n }\n stop() {\n this.linkInterceptor.stop();\n }\n willFollowLinkToLocation(link, location, originalEvent) {\n return (this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) &&\n link.hasAttribute(\"data-turbo-method\"));\n }\n followedLinkToLocation(link, location) {\n const form = document.createElement(\"form\");\n const type = \"hidden\";\n for (const [name, value] of location.searchParams) {\n form.append(Object.assign(document.createElement(\"input\"), { type, name, value }));\n }\n const action = Object.assign(location, { search: \"\" });\n form.setAttribute(\"data-turbo\", \"true\");\n form.setAttribute(\"action\", action.href);\n form.setAttribute(\"hidden\", \"\");\n const method = link.getAttribute(\"data-turbo-method\");\n if (method)\n form.setAttribute(\"method\", method);\n const turboFrame = link.getAttribute(\"data-turbo-frame\");\n if (turboFrame)\n form.setAttribute(\"data-turbo-frame\", turboFrame);\n const turboAction = getVisitAction(link);\n if (turboAction)\n form.setAttribute(\"data-turbo-action\", turboAction);\n const turboConfirm = link.getAttribute(\"data-turbo-confirm\");\n if (turboConfirm)\n form.setAttribute(\"data-turbo-confirm\", turboConfirm);\n const turboStream = link.hasAttribute(\"data-turbo-stream\");\n if (turboStream)\n form.setAttribute(\"data-turbo-stream\", \"\");\n this.delegate.submittedFormLinkToLocation(link, location, form);\n document.body.appendChild(form);\n form.addEventListener(\"turbo:submit-end\", () => form.remove(), { once: true });\n requestAnimationFrame(() => form.requestSubmit());\n }\n}\n\nclass Bardo {\n static async preservingPermanentElements(delegate, permanentElementMap, callback) {\n const bardo = new this(delegate, permanentElementMap);\n bardo.enter();\n await callback();\n bardo.leave();\n }\n constructor(delegate, permanentElementMap) {\n this.delegate = delegate;\n this.permanentElementMap = permanentElementMap;\n }\n enter() {\n for (const id in this.permanentElementMap) {\n const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];\n this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);\n this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);\n }\n }\n leave() {\n for (const id in this.permanentElementMap) {\n const [currentPermanentElement] = this.permanentElementMap[id];\n this.replaceCurrentPermanentElementWithClone(currentPermanentElement);\n this.replacePlaceholderWithPermanentElement(currentPermanentElement);\n this.delegate.leavingBardo(currentPermanentElement);\n }\n }\n replaceNewPermanentElementWithPlaceholder(permanentElement) {\n const placeholder = createPlaceholderForPermanentElement(permanentElement);\n permanentElement.replaceWith(placeholder);\n }\n replaceCurrentPermanentElementWithClone(permanentElement) {\n const clone = permanentElement.cloneNode(true);\n permanentElement.replaceWith(clone);\n }\n replacePlaceholderWithPermanentElement(permanentElement) {\n const placeholder = this.getPlaceholderById(permanentElement.id);\n placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement);\n }\n getPlaceholderById(id) {\n return this.placeholders.find((element) => element.content == id);\n }\n get placeholders() {\n return [...document.querySelectorAll(\"meta[name=turbo-permanent-placeholder][content]\")];\n }\n}\nfunction createPlaceholderForPermanentElement(permanentElement) {\n const element = document.createElement(\"meta\");\n element.setAttribute(\"name\", \"turbo-permanent-placeholder\");\n element.setAttribute(\"content\", permanentElement.id);\n return element;\n}\n\nclass Renderer {\n constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {\n this.activeElement = null;\n this.currentSnapshot = currentSnapshot;\n this.newSnapshot = newSnapshot;\n this.isPreview = isPreview;\n this.willRender = willRender;\n this.renderElement = renderElement;\n this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));\n }\n get shouldRender() {\n return true;\n }\n get reloadReason() {\n return;\n }\n prepareToRender() {\n return;\n }\n finishRendering() {\n if (this.resolvingFunctions) {\n this.resolvingFunctions.resolve();\n delete this.resolvingFunctions;\n }\n }\n async preservingPermanentElements(callback) {\n await Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);\n }\n focusFirstAutofocusableElement() {\n const element = this.connectedSnapshot.firstAutofocusableElement;\n if (elementIsFocusable(element)) {\n element.focus();\n }\n }\n enteringBardo(currentPermanentElement) {\n if (this.activeElement)\n return;\n if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {\n this.activeElement = this.currentSnapshot.activeElement;\n }\n }\n leavingBardo(currentPermanentElement) {\n if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) {\n this.activeElement.focus();\n this.activeElement = null;\n }\n }\n get connectedSnapshot() {\n return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot;\n }\n get currentElement() {\n return this.currentSnapshot.element;\n }\n get newElement() {\n return this.newSnapshot.element;\n }\n get permanentElementMap() {\n return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);\n }\n}\nfunction elementIsFocusable(element) {\n return element && typeof element.focus == \"function\";\n}\n\nclass FrameRenderer extends Renderer {\n static renderElement(currentElement, newElement) {\n var _a;\n const destinationRange = document.createRange();\n destinationRange.selectNodeContents(currentElement);\n destinationRange.deleteContents();\n const frameElement = newElement;\n const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();\n if (sourceRange) {\n sourceRange.selectNodeContents(frameElement);\n currentElement.appendChild(sourceRange.extractContents());\n }\n }\n constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {\n super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);\n this.delegate = delegate;\n }\n get shouldRender() {\n return true;\n }\n async render() {\n await nextAnimationFrame();\n this.preservingPermanentElements(() => {\n this.loadFrameElement();\n });\n this.scrollFrameIntoView();\n await nextAnimationFrame();\n this.focusFirstAutofocusableElement();\n await nextAnimationFrame();\n this.activateScriptElements();\n }\n loadFrameElement() {\n this.delegate.willRenderFrame(this.currentElement, this.newElement);\n this.renderElement(this.currentElement, this.newElement);\n }\n scrollFrameIntoView() {\n if (this.currentElement.autoscroll || this.newElement.autoscroll) {\n const element = this.currentElement.firstElementChild;\n const block = readScrollLogicalPosition(this.currentElement.getAttribute(\"data-autoscroll-block\"), \"end\");\n const behavior = readScrollBehavior(this.currentElement.getAttribute(\"data-autoscroll-behavior\"), \"auto\");\n if (element) {\n element.scrollIntoView({ block, behavior });\n return true;\n }\n }\n return false;\n }\n activateScriptElements() {\n for (const inertScriptElement of this.newScriptElements) {\n const activatedScriptElement = activateScriptElement(inertScriptElement);\n inertScriptElement.replaceWith(activatedScriptElement);\n }\n }\n get newScriptElements() {\n return this.currentElement.querySelectorAll(\"script\");\n }\n}\nfunction readScrollLogicalPosition(value, defaultValue) {\n if (value == \"end\" || value == \"start\" || value == \"center\" || value == \"nearest\") {\n return value;\n }\n else {\n return defaultValue;\n }\n}\nfunction readScrollBehavior(value, defaultValue) {\n if (value == \"auto\" || value == \"smooth\") {\n return value;\n }\n else {\n return defaultValue;\n }\n}\n\nclass ProgressBar {\n static get defaultCSS() {\n return unindent `\n .turbo-progress-bar {\n position: fixed;\n display: block;\n top: 0;\n left: 0;\n height: 3px;\n background: #0076ff;\n z-index: 2147483647;\n transition:\n width ${ProgressBar.animationDuration}ms ease-out,\n opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in;\n transform: translate3d(0, 0, 0);\n }\n `;\n }\n constructor() {\n this.hiding = false;\n this.value = 0;\n this.visible = false;\n this.trickle = () => {\n this.setValue(this.value + Math.random() / 100);\n };\n this.stylesheetElement = this.createStylesheetElement();\n this.progressElement = this.createProgressElement();\n this.installStylesheetElement();\n this.setValue(0);\n }\n show() {\n if (!this.visible) {\n this.visible = true;\n this.installProgressElement();\n this.startTrickling();\n }\n }\n hide() {\n if (this.visible && !this.hiding) {\n this.hiding = true;\n this.fadeProgressElement(() => {\n this.uninstallProgressElement();\n this.stopTrickling();\n this.visible = false;\n this.hiding = false;\n });\n }\n }\n setValue(value) {\n this.value = value;\n this.refresh();\n }\n installStylesheetElement() {\n document.head.insertBefore(this.stylesheetElement, document.head.firstChild);\n }\n installProgressElement() {\n this.progressElement.style.width = \"0\";\n this.progressElement.style.opacity = \"1\";\n document.documentElement.insertBefore(this.progressElement, document.body);\n this.refresh();\n }\n fadeProgressElement(callback) {\n this.progressElement.style.opacity = \"0\";\n setTimeout(callback, ProgressBar.animationDuration * 1.5);\n }\n uninstallProgressElement() {\n if (this.progressElement.parentNode) {\n document.documentElement.removeChild(this.progressElement);\n }\n }\n startTrickling() {\n if (!this.trickleInterval) {\n this.trickleInterval = window.setInterval(this.trickle, ProgressBar.animationDuration);\n }\n }\n stopTrickling() {\n window.clearInterval(this.trickleInterval);\n delete this.trickleInterval;\n }\n refresh() {\n requestAnimationFrame(() => {\n this.progressElement.style.width = `${10 + this.value * 90}%`;\n });\n }\n createStylesheetElement() {\n const element = document.createElement(\"style\");\n element.type = \"text/css\";\n element.textContent = ProgressBar.defaultCSS;\n if (this.cspNonce) {\n element.nonce = this.cspNonce;\n }\n return element;\n }\n createProgressElement() {\n const element = document.createElement(\"div\");\n element.className = \"turbo-progress-bar\";\n return element;\n }\n get cspNonce() {\n return getMetaContent(\"csp-nonce\");\n }\n}\nProgressBar.animationDuration = 300;\n\nclass HeadSnapshot extends Snapshot {\n constructor() {\n super(...arguments);\n this.detailsByOuterHTML = this.children\n .filter((element) => !elementIsNoscript(element))\n .map((element) => elementWithoutNonce(element))\n .reduce((result, element) => {\n const { outerHTML } = element;\n const details = outerHTML in result\n ? result[outerHTML]\n : {\n type: elementType(element),\n tracked: elementIsTracked(element),\n elements: [],\n };\n return Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) });\n }, {});\n }\n get trackedElementSignature() {\n return Object.keys(this.detailsByOuterHTML)\n .filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked)\n .join(\"\");\n }\n getScriptElementsNotInSnapshot(snapshot) {\n return this.getElementsMatchingTypeNotInSnapshot(\"script\", snapshot);\n }\n getStylesheetElementsNotInSnapshot(snapshot) {\n return this.getElementsMatchingTypeNotInSnapshot(\"stylesheet\", snapshot);\n }\n getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {\n return Object.keys(this.detailsByOuterHTML)\n .filter((outerHTML) => !(outerHTML in snapshot.detailsByOuterHTML))\n .map((outerHTML) => this.detailsByOuterHTML[outerHTML])\n .filter(({ type }) => type == matchedType)\n .map(({ elements: [element] }) => element);\n }\n get provisionalElements() {\n return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {\n const { type, tracked, elements } = this.detailsByOuterHTML[outerHTML];\n if (type == null && !tracked) {\n return [...result, ...elements];\n }\n else if (elements.length > 1) {\n return [...result, ...elements.slice(1)];\n }\n else {\n return result;\n }\n }, []);\n }\n getMetaValue(name) {\n const element = this.findMetaElementByName(name);\n return element ? element.getAttribute(\"content\") : null;\n }\n findMetaElementByName(name) {\n return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {\n const { elements: [element], } = this.detailsByOuterHTML[outerHTML];\n return elementIsMetaElementWithName(element, name) ? element : result;\n }, undefined);\n }\n}\nfunction elementType(element) {\n if (elementIsScript(element)) {\n return \"script\";\n }\n else if (elementIsStylesheet(element)) {\n return \"stylesheet\";\n }\n}\nfunction elementIsTracked(element) {\n return element.getAttribute(\"data-turbo-track\") == \"reload\";\n}\nfunction elementIsScript(element) {\n const tagName = element.localName;\n return tagName == \"script\";\n}\nfunction elementIsNoscript(element) {\n const tagName = element.localName;\n return tagName == \"noscript\";\n}\nfunction elementIsStylesheet(element) {\n const tagName = element.localName;\n return tagName == \"style\" || (tagName == \"link\" && element.getAttribute(\"rel\") == \"stylesheet\");\n}\nfunction elementIsMetaElementWithName(element, name) {\n const tagName = element.localName;\n return tagName == \"meta\" && element.getAttribute(\"name\") == name;\n}\nfunction elementWithoutNonce(element) {\n if (element.hasAttribute(\"nonce\")) {\n element.setAttribute(\"nonce\", \"\");\n }\n return element;\n}\n\nclass PageSnapshot extends Snapshot {\n static fromHTMLString(html = \"\") {\n return this.fromDocument(parseHTMLDocument(html));\n }\n static fromElement(element) {\n return this.fromDocument(element.ownerDocument);\n }\n static fromDocument({ head, body }) {\n return new this(body, new HeadSnapshot(head));\n }\n constructor(element, headSnapshot) {\n super(element);\n this.headSnapshot = headSnapshot;\n }\n clone() {\n const clonedElement = this.element.cloneNode(true);\n const selectElements = this.element.querySelectorAll(\"select\");\n const clonedSelectElements = clonedElement.querySelectorAll(\"select\");\n for (const [index, source] of selectElements.entries()) {\n const clone = clonedSelectElements[index];\n for (const option of clone.selectedOptions)\n option.selected = false;\n for (const option of source.selectedOptions)\n clone.options[option.index].selected = true;\n }\n for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type=\"password\"]')) {\n clonedPasswordInput.value = \"\";\n }\n return new PageSnapshot(clonedElement, this.headSnapshot);\n }\n get headElement() {\n return this.headSnapshot.element;\n }\n get rootLocation() {\n var _a;\n const root = (_a = this.getSetting(\"root\")) !== null && _a !== void 0 ? _a : \"/\";\n return expandURL(root);\n }\n get cacheControlValue() {\n return this.getSetting(\"cache-control\");\n }\n get isPreviewable() {\n return this.cacheControlValue != \"no-preview\";\n }\n get isCacheable() {\n return this.cacheControlValue != \"no-cache\";\n }\n get isVisitable() {\n return this.getSetting(\"visit-control\") != \"reload\";\n }\n getSetting(name) {\n return this.headSnapshot.getMetaValue(`turbo-${name}`);\n }\n}\n\nvar TimingMetric;\n(function (TimingMetric) {\n TimingMetric[\"visitStart\"] = \"visitStart\";\n TimingMetric[\"requestStart\"] = \"requestStart\";\n TimingMetric[\"requestEnd\"] = \"requestEnd\";\n TimingMetric[\"visitEnd\"] = \"visitEnd\";\n})(TimingMetric || (TimingMetric = {}));\nvar VisitState;\n(function (VisitState) {\n VisitState[\"initialized\"] = \"initialized\";\n VisitState[\"started\"] = \"started\";\n VisitState[\"canceled\"] = \"canceled\";\n VisitState[\"failed\"] = \"failed\";\n VisitState[\"completed\"] = \"completed\";\n})(VisitState || (VisitState = {}));\nconst defaultOptions = {\n action: \"advance\",\n historyChanged: false,\n visitCachedSnapshot: () => { },\n willRender: true,\n updateHistory: true,\n shouldCacheSnapshot: true,\n acceptsStreamResponse: false,\n};\nvar SystemStatusCode;\n(function (SystemStatusCode) {\n SystemStatusCode[SystemStatusCode[\"networkFailure\"] = 0] = \"networkFailure\";\n SystemStatusCode[SystemStatusCode[\"timeoutFailure\"] = -1] = \"timeoutFailure\";\n SystemStatusCode[SystemStatusCode[\"contentTypeMismatch\"] = -2] = \"contentTypeMismatch\";\n})(SystemStatusCode || (SystemStatusCode = {}));\nclass Visit {\n constructor(delegate, location, restorationIdentifier, options = {}) {\n this.identifier = uuid();\n this.timingMetrics = {};\n this.followedRedirect = false;\n this.historyChanged = false;\n this.scrolled = false;\n this.shouldCacheSnapshot = true;\n this.acceptsStreamResponse = false;\n this.snapshotCached = false;\n this.state = VisitState.initialized;\n this.delegate = delegate;\n this.location = location;\n this.restorationIdentifier = restorationIdentifier || uuid();\n const { action, historyChanged, referrer, snapshot, snapshotHTML, response, visitCachedSnapshot, willRender, updateHistory, shouldCacheSnapshot, acceptsStreamResponse, } = Object.assign(Object.assign({}, defaultOptions), options);\n this.action = action;\n this.historyChanged = historyChanged;\n this.referrer = referrer;\n this.snapshot = snapshot;\n this.snapshotHTML = snapshotHTML;\n this.response = response;\n this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);\n this.visitCachedSnapshot = visitCachedSnapshot;\n this.willRender = willRender;\n this.updateHistory = updateHistory;\n this.scrolled = !willRender;\n this.shouldCacheSnapshot = shouldCacheSnapshot;\n this.acceptsStreamResponse = acceptsStreamResponse;\n }\n get adapter() {\n return this.delegate.adapter;\n }\n get view() {\n return this.delegate.view;\n }\n get history() {\n return this.delegate.history;\n }\n get restorationData() {\n return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);\n }\n get silent() {\n return this.isSamePage;\n }\n start() {\n if (this.state == VisitState.initialized) {\n this.recordTimingMetric(TimingMetric.visitStart);\n this.state = VisitState.started;\n this.adapter.visitStarted(this);\n this.delegate.visitStarted(this);\n }\n }\n cancel() {\n if (this.state == VisitState.started) {\n if (this.request) {\n this.request.cancel();\n }\n this.cancelRender();\n this.state = VisitState.canceled;\n }\n }\n complete() {\n if (this.state == VisitState.started) {\n this.recordTimingMetric(TimingMetric.visitEnd);\n this.state = VisitState.completed;\n this.followRedirect();\n if (!this.followedRedirect) {\n this.adapter.visitCompleted(this);\n this.delegate.visitCompleted(this);\n }\n }\n }\n fail() {\n if (this.state == VisitState.started) {\n this.state = VisitState.failed;\n this.adapter.visitFailed(this);\n }\n }\n changeHistory() {\n var _a;\n if (!this.historyChanged && this.updateHistory) {\n const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? \"replace\" : this.action;\n const method = getHistoryMethodForAction(actionForHistory);\n this.history.update(method, this.location, this.restorationIdentifier);\n this.historyChanged = true;\n }\n }\n issueRequest() {\n if (this.hasPreloadedResponse()) {\n this.simulateRequest();\n }\n else if (this.shouldIssueRequest() && !this.request) {\n this.request = new FetchRequest(this, FetchMethod.get, this.location);\n this.request.perform();\n }\n }\n simulateRequest() {\n if (this.response) {\n this.startRequest();\n this.recordResponse();\n this.finishRequest();\n }\n }\n startRequest() {\n this.recordTimingMetric(TimingMetric.requestStart);\n this.adapter.visitRequestStarted(this);\n }\n recordResponse(response = this.response) {\n this.response = response;\n if (response) {\n const { statusCode } = response;\n if (isSuccessful(statusCode)) {\n this.adapter.visitRequestCompleted(this);\n }\n else {\n this.adapter.visitRequestFailedWithStatusCode(this, statusCode);\n }\n }\n }\n finishRequest() {\n this.recordTimingMetric(TimingMetric.requestEnd);\n this.adapter.visitRequestFinished(this);\n }\n loadResponse() {\n if (this.response) {\n const { statusCode, responseHTML } = this.response;\n this.render(async () => {\n if (this.shouldCacheSnapshot)\n this.cacheSnapshot();\n if (this.view.renderPromise)\n await this.view.renderPromise;\n if (isSuccessful(statusCode) && responseHTML != null) {\n await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender, this);\n this.performScroll();\n this.adapter.visitRendered(this);\n this.complete();\n }\n else {\n await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML), this);\n this.adapter.visitRendered(this);\n this.fail();\n }\n });\n }\n }\n getCachedSnapshot() {\n const snapshot = this.view.getCachedSnapshotForLocation(this.location) || this.getPreloadedSnapshot();\n if (snapshot && (!getAnchor(this.location) || snapshot.hasAnchor(getAnchor(this.location)))) {\n if (this.action == \"restore\" || snapshot.isPreviewable) {\n return snapshot;\n }\n }\n }\n getPreloadedSnapshot() {\n if (this.snapshotHTML) {\n return PageSnapshot.fromHTMLString(this.snapshotHTML);\n }\n }\n hasCachedSnapshot() {\n return this.getCachedSnapshot() != null;\n }\n loadCachedSnapshot() {\n const snapshot = this.getCachedSnapshot();\n if (snapshot) {\n const isPreview = this.shouldIssueRequest();\n this.render(async () => {\n this.cacheSnapshot();\n if (this.isSamePage) {\n this.adapter.visitRendered(this);\n }\n else {\n if (this.view.renderPromise)\n await this.view.renderPromise;\n await this.view.renderPage(snapshot, isPreview, this.willRender, this);\n this.performScroll();\n this.adapter.visitRendered(this);\n if (!isPreview) {\n this.complete();\n }\n }\n });\n }\n }\n followRedirect() {\n var _a;\n if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {\n this.adapter.visitProposedToLocation(this.redirectedToLocation, {\n action: \"replace\",\n response: this.response,\n shouldCacheSnapshot: false,\n willRender: false,\n });\n this.followedRedirect = true;\n }\n }\n goToSamePageAnchor() {\n if (this.isSamePage) {\n this.render(async () => {\n this.cacheSnapshot();\n this.performScroll();\n this.changeHistory();\n this.adapter.visitRendered(this);\n });\n }\n }\n prepareRequest(request) {\n if (this.acceptsStreamResponse) {\n request.acceptResponseType(StreamMessage.contentType);\n }\n }\n requestStarted() {\n this.startRequest();\n }\n requestPreventedHandlingResponse(_request, _response) { }\n async requestSucceededWithResponse(request, response) {\n const responseHTML = await response.responseHTML;\n const { redirected, statusCode } = response;\n if (responseHTML == undefined) {\n this.recordResponse({\n statusCode: SystemStatusCode.contentTypeMismatch,\n redirected,\n });\n }\n else {\n this.redirectedToLocation = response.redirected ? response.location : undefined;\n this.recordResponse({ statusCode: statusCode, responseHTML, redirected });\n }\n }\n async requestFailedWithResponse(request, response) {\n const responseHTML = await response.responseHTML;\n const { redirected, statusCode } = response;\n if (responseHTML == undefined) {\n this.recordResponse({\n statusCode: SystemStatusCode.contentTypeMismatch,\n redirected,\n });\n }\n else {\n this.recordResponse({ statusCode: statusCode, responseHTML, redirected });\n }\n }\n requestErrored(_request, _error) {\n this.recordResponse({\n statusCode: SystemStatusCode.networkFailure,\n redirected: false,\n });\n }\n requestFinished() {\n this.finishRequest();\n }\n performScroll() {\n if (!this.scrolled && !this.view.forceReloaded) {\n if (this.action == \"restore\") {\n this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();\n }\n else {\n this.scrollToAnchor() || this.view.scrollToTop();\n }\n if (this.isSamePage) {\n this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location);\n }\n this.scrolled = true;\n }\n }\n scrollToRestoredPosition() {\n const { scrollPosition } = this.restorationData;\n if (scrollPosition) {\n this.view.scrollToPosition(scrollPosition);\n return true;\n }\n }\n scrollToAnchor() {\n const anchor = getAnchor(this.location);\n if (anchor != null) {\n this.view.scrollToAnchor(anchor);\n return true;\n }\n }\n recordTimingMetric(metric) {\n this.timingMetrics[metric] = new Date().getTime();\n }\n getTimingMetrics() {\n return Object.assign({}, this.timingMetrics);\n }\n getHistoryMethodForAction(action) {\n switch (action) {\n case \"replace\":\n return history.replaceState;\n case \"advance\":\n case \"restore\":\n return history.pushState;\n }\n }\n hasPreloadedResponse() {\n return typeof this.response == \"object\";\n }\n shouldIssueRequest() {\n if (this.isSamePage) {\n return false;\n }\n else if (this.action == \"restore\") {\n return !this.hasCachedSnapshot();\n }\n else {\n return this.willRender;\n }\n }\n cacheSnapshot() {\n if (!this.snapshotCached) {\n this.view.cacheSnapshot(this.snapshot).then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot));\n this.snapshotCached = true;\n }\n }\n async render(callback) {\n this.cancelRender();\n await new Promise((resolve) => {\n this.frame = requestAnimationFrame(() => resolve());\n });\n await callback();\n delete this.frame;\n }\n cancelRender() {\n if (this.frame) {\n cancelAnimationFrame(this.frame);\n delete this.frame;\n }\n }\n}\nfunction isSuccessful(statusCode) {\n return statusCode >= 200 && statusCode < 300;\n}\n\nclass BrowserAdapter {\n constructor(session) {\n this.progressBar = new ProgressBar();\n this.showProgressBar = () => {\n this.progressBar.show();\n };\n this.session = session;\n }\n visitProposedToLocation(location, options) {\n this.navigator.startVisit(location, (options === null || options === void 0 ? void 0 : options.restorationIdentifier) || uuid(), options);\n }\n visitStarted(visit) {\n this.location = visit.location;\n visit.loadCachedSnapshot();\n visit.issueRequest();\n visit.goToSamePageAnchor();\n }\n visitRequestStarted(visit) {\n this.progressBar.setValue(0);\n if (visit.hasCachedSnapshot() || visit.action != \"restore\") {\n this.showVisitProgressBarAfterDelay();\n }\n else {\n this.showProgressBar();\n }\n }\n visitRequestCompleted(visit) {\n visit.loadResponse();\n }\n visitRequestFailedWithStatusCode(visit, statusCode) {\n switch (statusCode) {\n case SystemStatusCode.networkFailure:\n case SystemStatusCode.timeoutFailure:\n case SystemStatusCode.contentTypeMismatch:\n return this.reload({\n reason: \"request_failed\",\n context: {\n statusCode,\n },\n });\n default:\n return visit.loadResponse();\n }\n }\n visitRequestFinished(_visit) {\n this.progressBar.setValue(1);\n this.hideVisitProgressBar();\n }\n visitCompleted(_visit) { }\n pageInvalidated(reason) {\n this.reload(reason);\n }\n visitFailed(_visit) { }\n visitRendered(_visit) { }\n formSubmissionStarted(_formSubmission) {\n this.progressBar.setValue(0);\n this.showFormProgressBarAfterDelay();\n }\n formSubmissionFinished(_formSubmission) {\n this.progressBar.setValue(1);\n this.hideFormProgressBar();\n }\n showVisitProgressBarAfterDelay() {\n this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);\n }\n hideVisitProgressBar() {\n this.progressBar.hide();\n if (this.visitProgressBarTimeout != null) {\n window.clearTimeout(this.visitProgressBarTimeout);\n delete this.visitProgressBarTimeout;\n }\n }\n showFormProgressBarAfterDelay() {\n if (this.formProgressBarTimeout == null) {\n this.formProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);\n }\n }\n hideFormProgressBar() {\n this.progressBar.hide();\n if (this.formProgressBarTimeout != null) {\n window.clearTimeout(this.formProgressBarTimeout);\n delete this.formProgressBarTimeout;\n }\n }\n reload(reason) {\n var _a;\n dispatch(\"turbo:reload\", { detail: reason });\n window.location.href = ((_a = this.location) === null || _a === void 0 ? void 0 : _a.toString()) || window.location.href;\n }\n get navigator() {\n return this.session.navigator;\n }\n}\n\nclass CacheObserver {\n constructor() {\n this.selector = \"[data-turbo-temporary]\";\n this.deprecatedSelector = \"[data-turbo-cache=false]\";\n this.started = false;\n this.removeTemporaryElements = ((_event) => {\n for (const element of this.temporaryElements) {\n element.remove();\n }\n });\n }\n start() {\n if (!this.started) {\n this.started = true;\n addEventListener(\"turbo:before-cache\", this.removeTemporaryElements, false);\n }\n }\n stop() {\n if (this.started) {\n this.started = false;\n removeEventListener(\"turbo:before-cache\", this.removeTemporaryElements, false);\n }\n }\n get temporaryElements() {\n return [...document.querySelectorAll(this.selector), ...this.temporaryElementsWithDeprecation];\n }\n get temporaryElementsWithDeprecation() {\n const elements = document.querySelectorAll(this.deprecatedSelector);\n if (elements.length) {\n console.warn(`The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`);\n }\n return [...elements];\n }\n}\n\nclass FrameRedirector {\n constructor(session, element) {\n this.session = session;\n this.element = element;\n this.linkInterceptor = new LinkInterceptor(this, element);\n this.formSubmitObserver = new FormSubmitObserver(this, element);\n }\n start() {\n this.linkInterceptor.start();\n this.formSubmitObserver.start();\n }\n stop() {\n this.linkInterceptor.stop();\n this.formSubmitObserver.stop();\n }\n shouldInterceptLinkClick(element, _location, _event) {\n return this.shouldRedirect(element);\n }\n linkClickIntercepted(element, url, event) {\n const frame = this.findFrameElement(element);\n if (frame) {\n frame.delegate.linkClickIntercepted(element, url, event);\n }\n }\n willSubmitForm(element, submitter) {\n return (element.closest(\"turbo-frame\") == null &&\n this.shouldSubmit(element, submitter) &&\n this.shouldRedirect(element, submitter));\n }\n formSubmitted(element, submitter) {\n const frame = this.findFrameElement(element, submitter);\n if (frame) {\n frame.delegate.formSubmitted(element, submitter);\n }\n }\n shouldSubmit(form, submitter) {\n var _a;\n const action = getAction(form, submitter);\n const meta = this.element.ownerDocument.querySelector(`meta[name=\"turbo-root\"]`);\n const rootLocation = expandURL((_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : \"/\");\n return this.shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);\n }\n shouldRedirect(element, submitter) {\n const isNavigatable = element instanceof HTMLFormElement\n ? this.session.submissionIsNavigatable(element, submitter)\n : this.session.elementIsNavigatable(element);\n if (isNavigatable) {\n const frame = this.findFrameElement(element, submitter);\n return frame ? frame != element.closest(\"turbo-frame\") : false;\n }\n else {\n return false;\n }\n }\n findFrameElement(element, submitter) {\n const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute(\"data-turbo-frame\")) || element.getAttribute(\"data-turbo-frame\");\n if (id && id != \"_top\") {\n const frame = this.element.querySelector(`#${id}:not([disabled])`);\n if (frame instanceof FrameElement) {\n return frame;\n }\n }\n }\n}\n\nclass History {\n constructor(delegate) {\n this.restorationIdentifier = uuid();\n this.restorationData = {};\n this.started = false;\n this.pageLoaded = false;\n this.onPopState = (event) => {\n if (this.shouldHandlePopState()) {\n const { turbo } = event.state || {};\n if (turbo) {\n this.location = new URL(window.location.href);\n const { restorationIdentifier } = turbo;\n this.restorationIdentifier = restorationIdentifier;\n this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);\n }\n }\n };\n this.onPageLoad = async (_event) => {\n await nextMicrotask();\n this.pageLoaded = true;\n };\n this.delegate = delegate;\n }\n start() {\n if (!this.started) {\n addEventListener(\"popstate\", this.onPopState, false);\n addEventListener(\"load\", this.onPageLoad, false);\n this.started = true;\n this.replace(new URL(window.location.href));\n }\n }\n stop() {\n if (this.started) {\n removeEventListener(\"popstate\", this.onPopState, false);\n removeEventListener(\"load\", this.onPageLoad, false);\n this.started = false;\n }\n }\n push(location, restorationIdentifier) {\n this.update(history.pushState, location, restorationIdentifier);\n }\n replace(location, restorationIdentifier) {\n this.update(history.replaceState, location, restorationIdentifier);\n }\n update(method, location, restorationIdentifier = uuid()) {\n const state = { turbo: { restorationIdentifier } };\n method.call(history, state, \"\", location.href);\n this.location = location;\n this.restorationIdentifier = restorationIdentifier;\n }\n getRestorationDataForIdentifier(restorationIdentifier) {\n return this.restorationData[restorationIdentifier] || {};\n }\n updateRestorationData(additionalData) {\n const { restorationIdentifier } = this;\n const restorationData = this.restorationData[restorationIdentifier];\n this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData);\n }\n assumeControlOfScrollRestoration() {\n var _a;\n if (!this.previousScrollRestoration) {\n this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : \"auto\";\n history.scrollRestoration = \"manual\";\n }\n }\n relinquishControlOfScrollRestoration() {\n if (this.previousScrollRestoration) {\n history.scrollRestoration = this.previousScrollRestoration;\n delete this.previousScrollRestoration;\n }\n }\n shouldHandlePopState() {\n return this.pageIsLoaded();\n }\n pageIsLoaded() {\n return this.pageLoaded || document.readyState == \"complete\";\n }\n}\n\nclass Navigator {\n constructor(delegate) {\n this.delegate = delegate;\n }\n proposeVisit(location, options = {}) {\n if (this.delegate.allowsVisitingLocationWithAction(location, options.action)) {\n if (locationIsVisitable(location, this.view.snapshot.rootLocation)) {\n this.delegate.visitProposedToLocation(location, options);\n }\n else {\n window.location.href = location.toString();\n }\n }\n }\n startVisit(locatable, restorationIdentifier, options = {}) {\n this.stop();\n this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options));\n this.currentVisit.start();\n }\n submitForm(form, submitter) {\n this.stop();\n this.formSubmission = new FormSubmission(this, form, submitter, true);\n this.formSubmission.start();\n }\n stop() {\n if (this.formSubmission) {\n this.formSubmission.stop();\n delete this.formSubmission;\n }\n if (this.currentVisit) {\n this.currentVisit.cancel();\n delete this.currentVisit;\n }\n }\n get adapter() {\n return this.delegate.adapter;\n }\n get view() {\n return this.delegate.view;\n }\n get history() {\n return this.delegate.history;\n }\n formSubmissionStarted(formSubmission) {\n if (typeof this.adapter.formSubmissionStarted === \"function\") {\n this.adapter.formSubmissionStarted(formSubmission);\n }\n }\n async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) {\n if (formSubmission == this.formSubmission) {\n const responseHTML = await fetchResponse.responseHTML;\n if (responseHTML) {\n const shouldCacheSnapshot = formSubmission.isSafe;\n if (!shouldCacheSnapshot) {\n this.view.clearSnapshotCache();\n }\n const { statusCode, redirected } = fetchResponse;\n const action = this.getActionForFormSubmission(formSubmission);\n const visitOptions = {\n action,\n shouldCacheSnapshot,\n response: { statusCode, responseHTML, redirected },\n };\n this.proposeVisit(fetchResponse.location, visitOptions);\n }\n }\n }\n async formSubmissionFailedWithResponse(formSubmission, fetchResponse) {\n const responseHTML = await fetchResponse.responseHTML;\n if (responseHTML) {\n const snapshot = PageSnapshot.fromHTMLString(responseHTML);\n if (fetchResponse.serverError) {\n await this.view.renderError(snapshot, this.currentVisit);\n }\n else {\n await this.view.renderPage(snapshot, false, true, this.currentVisit);\n }\n this.view.scrollToTop();\n this.view.clearSnapshotCache();\n }\n }\n formSubmissionErrored(formSubmission, error) {\n console.error(error);\n }\n formSubmissionFinished(formSubmission) {\n if (typeof this.adapter.formSubmissionFinished === \"function\") {\n this.adapter.formSubmissionFinished(formSubmission);\n }\n }\n visitStarted(visit) {\n this.delegate.visitStarted(visit);\n }\n visitCompleted(visit) {\n this.delegate.visitCompleted(visit);\n }\n locationWithActionIsSamePage(location, action) {\n const anchor = getAnchor(location);\n const currentAnchor = getAnchor(this.view.lastRenderedLocation);\n const isRestorationToTop = action === \"restore\" && typeof anchor === \"undefined\";\n return (action !== \"replace\" &&\n getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) &&\n (isRestorationToTop || (anchor != null && anchor !== currentAnchor)));\n }\n visitScrolledToSamePageLocation(oldURL, newURL) {\n this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);\n }\n get location() {\n return this.history.location;\n }\n get restorationIdentifier() {\n return this.history.restorationIdentifier;\n }\n getActionForFormSubmission({ submitter, formElement }) {\n return getVisitAction(submitter, formElement) || \"advance\";\n }\n}\n\nvar PageStage;\n(function (PageStage) {\n PageStage[PageStage[\"initial\"] = 0] = \"initial\";\n PageStage[PageStage[\"loading\"] = 1] = \"loading\";\n PageStage[PageStage[\"interactive\"] = 2] = \"interactive\";\n PageStage[PageStage[\"complete\"] = 3] = \"complete\";\n})(PageStage || (PageStage = {}));\nclass PageObserver {\n constructor(delegate) {\n this.stage = PageStage.initial;\n this.started = false;\n this.interpretReadyState = () => {\n const { readyState } = this;\n if (readyState == \"interactive\") {\n this.pageIsInteractive();\n }\n else if (readyState == \"complete\") {\n this.pageIsComplete();\n }\n };\n this.pageWillUnload = () => {\n this.delegate.pageWillUnload();\n };\n this.delegate = delegate;\n }\n start() {\n if (!this.started) {\n if (this.stage == PageStage.initial) {\n this.stage = PageStage.loading;\n }\n document.addEventListener(\"readystatechange\", this.interpretReadyState, false);\n addEventListener(\"pagehide\", this.pageWillUnload, false);\n this.started = true;\n }\n }\n stop() {\n if (this.started) {\n document.removeEventListener(\"readystatechange\", this.interpretReadyState, false);\n removeEventListener(\"pagehide\", this.pageWillUnload, false);\n this.started = false;\n }\n }\n pageIsInteractive() {\n if (this.stage == PageStage.loading) {\n this.stage = PageStage.interactive;\n this.delegate.pageBecameInteractive();\n }\n }\n pageIsComplete() {\n this.pageIsInteractive();\n if (this.stage == PageStage.interactive) {\n this.stage = PageStage.complete;\n this.delegate.pageLoaded();\n }\n }\n get readyState() {\n return document.readyState;\n }\n}\n\nclass ScrollObserver {\n constructor(delegate) {\n this.started = false;\n this.onScroll = () => {\n this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });\n };\n this.delegate = delegate;\n }\n start() {\n if (!this.started) {\n addEventListener(\"scroll\", this.onScroll, false);\n this.onScroll();\n this.started = true;\n }\n }\n stop() {\n if (this.started) {\n removeEventListener(\"scroll\", this.onScroll, false);\n this.started = false;\n }\n }\n updatePosition(position) {\n this.delegate.scrollPositionChanged(position);\n }\n}\n\nclass StreamMessageRenderer {\n render({ fragment }) {\n Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () => document.documentElement.appendChild(fragment));\n }\n enteringBardo(currentPermanentElement, newPermanentElement) {\n newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));\n }\n leavingBardo() { }\n}\nfunction getPermanentElementMapForFragment(fragment) {\n const permanentElementsInDocument = queryPermanentElementsAll(document.documentElement);\n const permanentElementMap = {};\n for (const permanentElementInDocument of permanentElementsInDocument) {\n const { id } = permanentElementInDocument;\n for (const streamElement of fragment.querySelectorAll(\"turbo-stream\")) {\n const elementInStream = getPermanentElementById(streamElement.templateElement.content, id);\n if (elementInStream) {\n permanentElementMap[id] = [permanentElementInDocument, elementInStream];\n }\n }\n }\n return permanentElementMap;\n}\n\nclass StreamObserver {\n constructor(delegate) {\n this.sources = new Set();\n this.started = false;\n this.inspectFetchResponse = ((event) => {\n const response = fetchResponseFromEvent(event);\n if (response && fetchResponseIsStream(response)) {\n event.preventDefault();\n this.receiveMessageResponse(response);\n }\n });\n this.receiveMessageEvent = (event) => {\n if (this.started && typeof event.data == \"string\") {\n this.receiveMessageHTML(event.data);\n }\n };\n this.delegate = delegate;\n }\n start() {\n if (!this.started) {\n this.started = true;\n addEventListener(\"turbo:before-fetch-response\", this.inspectFetchResponse, false);\n }\n }\n stop() {\n if (this.started) {\n this.started = false;\n removeEventListener(\"turbo:before-fetch-response\", this.inspectFetchResponse, false);\n }\n }\n connectStreamSource(source) {\n if (!this.streamSourceIsConnected(source)) {\n this.sources.add(source);\n source.addEventListener(\"message\", this.receiveMessageEvent, false);\n }\n }\n disconnectStreamSource(source) {\n if (this.streamSourceIsConnected(source)) {\n this.sources.delete(source);\n source.removeEventListener(\"message\", this.receiveMessageEvent, false);\n }\n }\n streamSourceIsConnected(source) {\n return this.sources.has(source);\n }\n async receiveMessageResponse(response) {\n const html = await response.responseHTML;\n if (html) {\n this.receiveMessageHTML(html);\n }\n }\n receiveMessageHTML(html) {\n this.delegate.receivedMessageFromStream(StreamMessage.wrap(html));\n }\n}\nfunction fetchResponseFromEvent(event) {\n var _a;\n const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse;\n if (fetchResponse instanceof FetchResponse) {\n return fetchResponse;\n }\n}\nfunction fetchResponseIsStream(response) {\n var _a;\n const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : \"\";\n return contentType.startsWith(StreamMessage.contentType);\n}\n\nclass ErrorRenderer extends Renderer {\n static renderElement(currentElement, newElement) {\n const { documentElement, body } = document;\n documentElement.replaceChild(newElement, body);\n }\n async render() {\n this.replaceHeadAndBody();\n this.activateScriptElements();\n }\n replaceHeadAndBody() {\n const { documentElement, head } = document;\n documentElement.replaceChild(this.newHead, head);\n this.renderElement(this.currentElement, this.newElement);\n }\n activateScriptElements() {\n for (const replaceableElement of this.scriptElements) {\n const parentNode = replaceableElement.parentNode;\n if (parentNode) {\n const element = activateScriptElement(replaceableElement);\n parentNode.replaceChild(element, replaceableElement);\n }\n }\n }\n get newHead() {\n return this.newSnapshot.headSnapshot.element;\n }\n get scriptElements() {\n return document.documentElement.querySelectorAll(\"script\");\n }\n}\n\nclass PageRenderer extends Renderer {\n static renderElement(currentElement, newElement) {\n if (document.body && newElement instanceof HTMLBodyElement) {\n document.body.replaceWith(newElement);\n }\n else {\n document.documentElement.appendChild(newElement);\n }\n }\n get shouldRender() {\n return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;\n }\n get reloadReason() {\n if (!this.newSnapshot.isVisitable) {\n return {\n reason: \"turbo_visit_control_is_reload\",\n };\n }\n if (!this.trackedElementsAreIdentical) {\n return {\n reason: \"tracked_element_mismatch\",\n };\n }\n }\n async prepareToRender() {\n await this.mergeHead();\n }\n async render() {\n if (this.willRender) {\n await this.replaceBody();\n }\n }\n finishRendering() {\n super.finishRendering();\n if (!this.isPreview) {\n this.focusFirstAutofocusableElement();\n }\n }\n get currentHeadSnapshot() {\n return this.currentSnapshot.headSnapshot;\n }\n get newHeadSnapshot() {\n return this.newSnapshot.headSnapshot;\n }\n get newElement() {\n return this.newSnapshot.element;\n }\n async mergeHead() {\n const mergedHeadElements = this.mergeProvisionalElements();\n const newStylesheetElements = this.copyNewHeadStylesheetElements();\n this.copyNewHeadScriptElements();\n await mergedHeadElements;\n await newStylesheetElements;\n }\n async replaceBody() {\n await this.preservingPermanentElements(async () => {\n this.activateNewBody();\n await this.assignNewBody();\n });\n }\n get trackedElementsAreIdentical() {\n return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature;\n }\n async copyNewHeadStylesheetElements() {\n const loadingElements = [];\n for (const element of this.newHeadStylesheetElements) {\n loadingElements.push(waitForLoad(element));\n document.head.appendChild(element);\n }\n await Promise.all(loadingElements);\n }\n copyNewHeadScriptElements() {\n for (const element of this.newHeadScriptElements) {\n document.head.appendChild(activateScriptElement(element));\n }\n }\n async mergeProvisionalElements() {\n const newHeadElements = [...this.newHeadProvisionalElements];\n for (const element of this.currentHeadProvisionalElements) {\n if (!this.isCurrentElementInElementList(element, newHeadElements)) {\n document.head.removeChild(element);\n }\n }\n for (const element of newHeadElements) {\n document.head.appendChild(element);\n }\n }\n isCurrentElementInElementList(element, elementList) {\n for (const [index, newElement] of elementList.entries()) {\n if (element.tagName == \"TITLE\") {\n if (newElement.tagName != \"TITLE\") {\n continue;\n }\n if (element.innerHTML == newElement.innerHTML) {\n elementList.splice(index, 1);\n return true;\n }\n }\n if (newElement.isEqualNode(element)) {\n elementList.splice(index, 1);\n return true;\n }\n }\n return false;\n }\n removeCurrentHeadProvisionalElements() {\n for (const element of this.currentHeadProvisionalElements) {\n document.head.removeChild(element);\n }\n }\n copyNewHeadProvisionalElements() {\n for (const element of this.newHeadProvisionalElements) {\n document.head.appendChild(element);\n }\n }\n activateNewBody() {\n document.adoptNode(this.newElement);\n this.activateNewBodyScriptElements();\n }\n activateNewBodyScriptElements() {\n for (const inertScriptElement of this.newBodyScriptElements) {\n const activatedScriptElement = activateScriptElement(inertScriptElement);\n inertScriptElement.replaceWith(activatedScriptElement);\n }\n }\n async assignNewBody() {\n await this.renderElement(this.currentElement, this.newElement);\n }\n get newHeadStylesheetElements() {\n return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);\n }\n get newHeadScriptElements() {\n return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot);\n }\n get currentHeadProvisionalElements() {\n return this.currentHeadSnapshot.provisionalElements;\n }\n get newHeadProvisionalElements() {\n return this.newHeadSnapshot.provisionalElements;\n }\n get newBodyScriptElements() {\n return this.newElement.querySelectorAll(\"script\");\n }\n}\n\nclass SnapshotCache {\n constructor(size) {\n this.keys = [];\n this.snapshots = {};\n this.size = size;\n }\n has(location) {\n return toCacheKey(location) in this.snapshots;\n }\n get(location) {\n if (this.has(location)) {\n const snapshot = this.read(location);\n this.touch(location);\n return snapshot;\n }\n }\n put(location, snapshot) {\n this.write(location, snapshot);\n this.touch(location);\n return snapshot;\n }\n clear() {\n this.snapshots = {};\n }\n read(location) {\n return this.snapshots[toCacheKey(location)];\n }\n write(location, snapshot) {\n this.snapshots[toCacheKey(location)] = snapshot;\n }\n touch(location) {\n const key = toCacheKey(location);\n const index = this.keys.indexOf(key);\n if (index > -1)\n this.keys.splice(index, 1);\n this.keys.unshift(key);\n this.trim();\n }\n trim() {\n for (const key of this.keys.splice(this.size)) {\n delete this.snapshots[key];\n }\n }\n}\n\nclass PageView extends View {\n constructor() {\n super(...arguments);\n this.snapshotCache = new SnapshotCache(10);\n this.lastRenderedLocation = new URL(location.href);\n this.forceReloaded = false;\n }\n renderPage(snapshot, isPreview = false, willRender = true, visit) {\n const renderer = new PageRenderer(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);\n if (!renderer.shouldRender) {\n this.forceReloaded = true;\n }\n else {\n visit === null || visit === void 0 ? void 0 : visit.changeHistory();\n }\n return this.render(renderer);\n }\n renderError(snapshot, visit) {\n visit === null || visit === void 0 ? void 0 : visit.changeHistory();\n const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);\n return this.render(renderer);\n }\n clearSnapshotCache() {\n this.snapshotCache.clear();\n }\n async cacheSnapshot(snapshot = this.snapshot) {\n if (snapshot.isCacheable) {\n this.delegate.viewWillCacheSnapshot();\n const { lastRenderedLocation: location } = this;\n await nextEventLoopTick();\n const cachedSnapshot = snapshot.clone();\n this.snapshotCache.put(location, cachedSnapshot);\n return cachedSnapshot;\n }\n }\n getCachedSnapshotForLocation(location) {\n return this.snapshotCache.get(location);\n }\n get snapshot() {\n return PageSnapshot.fromElement(this.element);\n }\n}\n\nclass Preloader {\n constructor(delegate) {\n this.selector = \"a[data-turbo-preload]\";\n this.delegate = delegate;\n }\n get snapshotCache() {\n return this.delegate.navigator.view.snapshotCache;\n }\n start() {\n if (document.readyState === \"loading\") {\n return document.addEventListener(\"DOMContentLoaded\", () => {\n this.preloadOnLoadLinksForView(document.body);\n });\n }\n else {\n this.preloadOnLoadLinksForView(document.body);\n }\n }\n preloadOnLoadLinksForView(element) {\n for (const link of element.querySelectorAll(this.selector)) {\n this.preloadURL(link);\n }\n }\n async preloadURL(link) {\n const location = new URL(link.href);\n if (this.snapshotCache.has(location)) {\n return;\n }\n try {\n const response = await fetch(location.toString(), { headers: { \"VND.PREFETCH\": \"true\", Accept: \"text/html\" } });\n const responseText = await response.text();\n const snapshot = PageSnapshot.fromHTMLString(responseText);\n this.snapshotCache.put(location, snapshot);\n }\n catch (_) {\n }\n }\n}\n\nclass Session {\n constructor() {\n this.navigator = new Navigator(this);\n this.history = new History(this);\n this.preloader = new Preloader(this);\n this.view = new PageView(this, document.documentElement);\n this.adapter = new BrowserAdapter(this);\n this.pageObserver = new PageObserver(this);\n this.cacheObserver = new CacheObserver();\n this.linkClickObserver = new LinkClickObserver(this, window);\n this.formSubmitObserver = new FormSubmitObserver(this, document);\n this.scrollObserver = new ScrollObserver(this);\n this.streamObserver = new StreamObserver(this);\n this.formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);\n this.frameRedirector = new FrameRedirector(this, document.documentElement);\n this.streamMessageRenderer = new StreamMessageRenderer();\n this.drive = true;\n this.enabled = true;\n this.progressBarDelay = 500;\n this.started = false;\n this.formMode = \"on\";\n }\n start() {\n if (!this.started) {\n this.pageObserver.start();\n this.cacheObserver.start();\n this.formLinkClickObserver.start();\n this.linkClickObserver.start();\n this.formSubmitObserver.start();\n this.scrollObserver.start();\n this.streamObserver.start();\n this.frameRedirector.start();\n this.history.start();\n this.preloader.start();\n this.started = true;\n this.enabled = true;\n }\n }\n disable() {\n this.enabled = false;\n }\n stop() {\n if (this.started) {\n this.pageObserver.stop();\n this.cacheObserver.stop();\n this.formLinkClickObserver.stop();\n this.linkClickObserver.stop();\n this.formSubmitObserver.stop();\n this.scrollObserver.stop();\n this.streamObserver.stop();\n this.frameRedirector.stop();\n this.history.stop();\n this.started = false;\n }\n }\n registerAdapter(adapter) {\n this.adapter = adapter;\n }\n visit(location, options = {}) {\n const frameElement = options.frame ? document.getElementById(options.frame) : null;\n if (frameElement instanceof FrameElement) {\n frameElement.src = location.toString();\n frameElement.loaded;\n }\n else {\n this.navigator.proposeVisit(expandURL(location), options);\n }\n }\n connectStreamSource(source) {\n this.streamObserver.connectStreamSource(source);\n }\n disconnectStreamSource(source) {\n this.streamObserver.disconnectStreamSource(source);\n }\n renderStreamMessage(message) {\n this.streamMessageRenderer.render(StreamMessage.wrap(message));\n }\n clearCache() {\n this.view.clearSnapshotCache();\n }\n setProgressBarDelay(delay) {\n this.progressBarDelay = delay;\n }\n setFormMode(mode) {\n this.formMode = mode;\n }\n get location() {\n return this.history.location;\n }\n get restorationIdentifier() {\n return this.history.restorationIdentifier;\n }\n historyPoppedToLocationWithRestorationIdentifier(location, restorationIdentifier) {\n if (this.enabled) {\n this.navigator.startVisit(location, restorationIdentifier, {\n action: \"restore\",\n historyChanged: true,\n });\n }\n else {\n this.adapter.pageInvalidated({\n reason: \"turbo_disabled\",\n });\n }\n }\n scrollPositionChanged(position) {\n this.history.updateRestorationData({ scrollPosition: position });\n }\n willSubmitFormLinkToLocation(link, location) {\n return this.elementIsNavigatable(link) && locationIsVisitable(location, this.snapshot.rootLocation);\n }\n submittedFormLinkToLocation() { }\n willFollowLinkToLocation(link, location, event) {\n return (this.elementIsNavigatable(link) &&\n locationIsVisitable(location, this.snapshot.rootLocation) &&\n this.applicationAllowsFollowingLinkToLocation(link, location, event));\n }\n followedLinkToLocation(link, location) {\n const action = this.getActionForLink(link);\n const acceptsStreamResponse = link.hasAttribute(\"data-turbo-stream\");\n this.visit(location.href, { action, acceptsStreamResponse });\n }\n allowsVisitingLocationWithAction(location, action) {\n return this.locationWithActionIsSamePage(location, action) || this.applicationAllowsVisitingLocation(location);\n }\n visitProposedToLocation(location, options) {\n extendURLWithDeprecatedProperties(location);\n this.adapter.visitProposedToLocation(location, options);\n }\n visitStarted(visit) {\n if (!visit.acceptsStreamResponse) {\n markAsBusy(document.documentElement);\n }\n extendURLWithDeprecatedProperties(visit.location);\n if (!visit.silent) {\n this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);\n }\n }\n visitCompleted(visit) {\n clearBusyState(document.documentElement);\n this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());\n }\n locationWithActionIsSamePage(location, action) {\n return this.navigator.locationWithActionIsSamePage(location, action);\n }\n visitScrolledToSamePageLocation(oldURL, newURL) {\n this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);\n }\n willSubmitForm(form, submitter) {\n const action = getAction(form, submitter);\n return (this.submissionIsNavigatable(form, submitter) &&\n locationIsVisitable(expandURL(action), this.snapshot.rootLocation));\n }\n formSubmitted(form, submitter) {\n this.navigator.submitForm(form, submitter);\n }\n pageBecameInteractive() {\n this.view.lastRenderedLocation = this.location;\n this.notifyApplicationAfterPageLoad();\n }\n pageLoaded() {\n this.history.assumeControlOfScrollRestoration();\n }\n pageWillUnload() {\n this.history.relinquishControlOfScrollRestoration();\n }\n receivedMessageFromStream(message) {\n this.renderStreamMessage(message);\n }\n viewWillCacheSnapshot() {\n var _a;\n if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) {\n this.notifyApplicationBeforeCachingSnapshot();\n }\n }\n allowsImmediateRender({ element }, options) {\n const event = this.notifyApplicationBeforeRender(element, options);\n const { defaultPrevented, detail: { render }, } = event;\n if (this.view.renderer && render) {\n this.view.renderer.renderElement = render;\n }\n return !defaultPrevented;\n }\n viewRenderedSnapshot(_snapshot, _isPreview) {\n this.view.lastRenderedLocation = this.history.location;\n this.notifyApplicationAfterRender();\n }\n preloadOnLoadLinksForView(element) {\n this.preloader.preloadOnLoadLinksForView(element);\n }\n viewInvalidated(reason) {\n this.adapter.pageInvalidated(reason);\n }\n frameLoaded(frame) {\n this.notifyApplicationAfterFrameLoad(frame);\n }\n frameRendered(fetchResponse, frame) {\n this.notifyApplicationAfterFrameRender(fetchResponse, frame);\n }\n applicationAllowsFollowingLinkToLocation(link, location, ev) {\n const event = this.notifyApplicationAfterClickingLinkToLocation(link, location, ev);\n return !event.defaultPrevented;\n }\n applicationAllowsVisitingLocation(location) {\n const event = this.notifyApplicationBeforeVisitingLocation(location);\n return !event.defaultPrevented;\n }\n notifyApplicationAfterClickingLinkToLocation(link, location, event) {\n return dispatch(\"turbo:click\", {\n target: link,\n detail: { url: location.href, originalEvent: event },\n cancelable: true,\n });\n }\n notifyApplicationBeforeVisitingLocation(location) {\n return dispatch(\"turbo:before-visit\", {\n detail: { url: location.href },\n cancelable: true,\n });\n }\n notifyApplicationAfterVisitingLocation(location, action) {\n return dispatch(\"turbo:visit\", { detail: { url: location.href, action } });\n }\n notifyApplicationBeforeCachingSnapshot() {\n return dispatch(\"turbo:before-cache\");\n }\n notifyApplicationBeforeRender(newBody, options) {\n return dispatch(\"turbo:before-render\", {\n detail: Object.assign({ newBody }, options),\n cancelable: true,\n });\n }\n notifyApplicationAfterRender() {\n return dispatch(\"turbo:render\");\n }\n notifyApplicationAfterPageLoad(timing = {}) {\n return dispatch(\"turbo:load\", {\n detail: { url: this.location.href, timing },\n });\n }\n notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {\n dispatchEvent(new HashChangeEvent(\"hashchange\", {\n oldURL: oldURL.toString(),\n newURL: newURL.toString(),\n }));\n }\n notifyApplicationAfterFrameLoad(frame) {\n return dispatch(\"turbo:frame-load\", { target: frame });\n }\n notifyApplicationAfterFrameRender(fetchResponse, frame) {\n return dispatch(\"turbo:frame-render\", {\n detail: { fetchResponse },\n target: frame,\n cancelable: true,\n });\n }\n submissionIsNavigatable(form, submitter) {\n if (this.formMode == \"off\") {\n return false;\n }\n else {\n const submitterIsNavigatable = submitter ? this.elementIsNavigatable(submitter) : true;\n if (this.formMode == \"optin\") {\n return submitterIsNavigatable && form.closest('[data-turbo=\"true\"]') != null;\n }\n else {\n return submitterIsNavigatable && this.elementIsNavigatable(form);\n }\n }\n }\n elementIsNavigatable(element) {\n const container = findClosestRecursively(element, \"[data-turbo]\");\n const withinFrame = findClosestRecursively(element, \"turbo-frame\");\n if (this.drive || withinFrame) {\n if (container) {\n return container.getAttribute(\"data-turbo\") != \"false\";\n }\n else {\n return true;\n }\n }\n else {\n if (container) {\n return container.getAttribute(\"data-turbo\") == \"true\";\n }\n else {\n return false;\n }\n }\n }\n getActionForLink(link) {\n return getVisitAction(link) || \"advance\";\n }\n get snapshot() {\n return this.view.snapshot;\n }\n}\nfunction extendURLWithDeprecatedProperties(url) {\n Object.defineProperties(url, deprecatedLocationPropertyDescriptors);\n}\nconst deprecatedLocationPropertyDescriptors = {\n absoluteURL: {\n get() {\n return this.toString();\n },\n },\n};\n\nclass Cache {\n constructor(session) {\n this.session = session;\n }\n clear() {\n this.session.clearCache();\n }\n resetCacheControl() {\n this.setCacheControl(\"\");\n }\n exemptPageFromCache() {\n this.setCacheControl(\"no-cache\");\n }\n exemptPageFromPreview() {\n this.setCacheControl(\"no-preview\");\n }\n setCacheControl(value) {\n setMetaContent(\"turbo-cache-control\", value);\n }\n}\n\nconst StreamActions = {\n after() {\n this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); });\n },\n append() {\n this.removeDuplicateTargetChildren();\n this.targetElements.forEach((e) => e.append(this.templateContent));\n },\n before() {\n this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); });\n },\n prepend() {\n this.removeDuplicateTargetChildren();\n this.targetElements.forEach((e) => e.prepend(this.templateContent));\n },\n remove() {\n this.targetElements.forEach((e) => e.remove());\n },\n replace() {\n this.targetElements.forEach((e) => e.replaceWith(this.templateContent));\n },\n update() {\n this.targetElements.forEach((targetElement) => {\n targetElement.innerHTML = \"\";\n targetElement.append(this.templateContent);\n });\n },\n};\n\nconst session = new Session();\nconst cache = new Cache(session);\nconst { navigator: navigator$1 } = session;\nfunction start() {\n session.start();\n}\nfunction registerAdapter(adapter) {\n session.registerAdapter(adapter);\n}\nfunction visit(location, options) {\n session.visit(location, options);\n}\nfunction connectStreamSource(source) {\n session.connectStreamSource(source);\n}\nfunction disconnectStreamSource(source) {\n session.disconnectStreamSource(source);\n}\nfunction renderStreamMessage(message) {\n session.renderStreamMessage(message);\n}\nfunction clearCache() {\n console.warn(\"Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`\");\n session.clearCache();\n}\nfunction setProgressBarDelay(delay) {\n session.setProgressBarDelay(delay);\n}\nfunction setConfirmMethod(confirmMethod) {\n FormSubmission.confirmMethod = confirmMethod;\n}\nfunction setFormMode(mode) {\n session.setFormMode(mode);\n}\n\nvar Turbo = /*#__PURE__*/Object.freeze({\n __proto__: null,\n navigator: navigator$1,\n session: session,\n cache: cache,\n PageRenderer: PageRenderer,\n PageSnapshot: PageSnapshot,\n FrameRenderer: FrameRenderer,\n start: start,\n registerAdapter: registerAdapter,\n visit: visit,\n connectStreamSource: connectStreamSource,\n disconnectStreamSource: disconnectStreamSource,\n renderStreamMessage: renderStreamMessage,\n clearCache: clearCache,\n setProgressBarDelay: setProgressBarDelay,\n setConfirmMethod: setConfirmMethod,\n setFormMode: setFormMode,\n StreamActions: StreamActions\n});\n\nclass TurboFrameMissingError extends Error {\n}\n\nclass FrameController {\n constructor(element) {\n this.fetchResponseLoaded = (_fetchResponse) => { };\n this.currentFetchRequest = null;\n this.resolveVisitPromise = () => { };\n this.connected = false;\n this.hasBeenLoaded = false;\n this.ignoredAttributes = new Set();\n this.action = null;\n this.visitCachedSnapshot = ({ element }) => {\n const frame = element.querySelector(\"#\" + this.element.id);\n if (frame && this.previousFrameElement) {\n frame.replaceChildren(...this.previousFrameElement.children);\n }\n delete this.previousFrameElement;\n };\n this.element = element;\n this.view = new FrameView(this, this.element);\n this.appearanceObserver = new AppearanceObserver(this, this.element);\n this.formLinkClickObserver = new FormLinkClickObserver(this, this.element);\n this.linkInterceptor = new LinkInterceptor(this, this.element);\n this.restorationIdentifier = uuid();\n this.formSubmitObserver = new FormSubmitObserver(this, this.element);\n }\n connect() {\n if (!this.connected) {\n this.connected = true;\n if (this.loadingStyle == FrameLoadingStyle.lazy) {\n this.appearanceObserver.start();\n }\n else {\n this.loadSourceURL();\n }\n this.formLinkClickObserver.start();\n this.linkInterceptor.start();\n this.formSubmitObserver.start();\n }\n }\n disconnect() {\n if (this.connected) {\n this.connected = false;\n this.appearanceObserver.stop();\n this.formLinkClickObserver.stop();\n this.linkInterceptor.stop();\n this.formSubmitObserver.stop();\n }\n }\n disabledChanged() {\n if (this.loadingStyle == FrameLoadingStyle.eager) {\n this.loadSourceURL();\n }\n }\n sourceURLChanged() {\n if (this.isIgnoringChangesTo(\"src\"))\n return;\n if (this.element.isConnected) {\n this.complete = false;\n }\n if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {\n this.loadSourceURL();\n }\n }\n sourceURLReloaded() {\n const { src } = this.element;\n this.ignoringChangesToAttribute(\"complete\", () => {\n this.element.removeAttribute(\"complete\");\n });\n this.element.src = null;\n this.element.src = src;\n return this.element.loaded;\n }\n completeChanged() {\n if (this.isIgnoringChangesTo(\"complete\"))\n return;\n this.loadSourceURL();\n }\n loadingStyleChanged() {\n if (this.loadingStyle == FrameLoadingStyle.lazy) {\n this.appearanceObserver.start();\n }\n else {\n this.appearanceObserver.stop();\n this.loadSourceURL();\n }\n }\n async loadSourceURL() {\n if (this.enabled && this.isActive && !this.complete && this.sourceURL) {\n this.element.loaded = this.visit(expandURL(this.sourceURL));\n this.appearanceObserver.stop();\n await this.element.loaded;\n this.hasBeenLoaded = true;\n }\n }\n async loadResponse(fetchResponse) {\n if (fetchResponse.redirected || (fetchResponse.succeeded && fetchResponse.isHTML)) {\n this.sourceURL = fetchResponse.response.url;\n }\n try {\n const html = await fetchResponse.responseHTML;\n if (html) {\n const document = parseHTMLDocument(html);\n const pageSnapshot = PageSnapshot.fromDocument(document);\n if (pageSnapshot.isVisitable) {\n await this.loadFrameResponse(fetchResponse, document);\n }\n else {\n await this.handleUnvisitableFrameResponse(fetchResponse);\n }\n }\n }\n finally {\n this.fetchResponseLoaded = () => { };\n }\n }\n elementAppearedInViewport(element) {\n this.proposeVisitIfNavigatedWithAction(element, element);\n this.loadSourceURL();\n }\n willSubmitFormLinkToLocation(link) {\n return this.shouldInterceptNavigation(link);\n }\n submittedFormLinkToLocation(link, _location, form) {\n const frame = this.findFrameElement(link);\n if (frame)\n form.setAttribute(\"data-turbo-frame\", frame.id);\n }\n shouldInterceptLinkClick(element, _location, _event) {\n return this.shouldInterceptNavigation(element);\n }\n linkClickIntercepted(element, location) {\n this.navigateFrame(element, location);\n }\n willSubmitForm(element, submitter) {\n return element.closest(\"turbo-frame\") == this.element && this.shouldInterceptNavigation(element, submitter);\n }\n formSubmitted(element, submitter) {\n if (this.formSubmission) {\n this.formSubmission.stop();\n }\n this.formSubmission = new FormSubmission(this, element, submitter);\n const { fetchRequest } = this.formSubmission;\n this.prepareRequest(fetchRequest);\n this.formSubmission.start();\n }\n prepareRequest(request) {\n var _a;\n request.headers[\"Turbo-Frame\"] = this.id;\n if ((_a = this.currentNavigationElement) === null || _a === void 0 ? void 0 : _a.hasAttribute(\"data-turbo-stream\")) {\n request.acceptResponseType(StreamMessage.contentType);\n }\n }\n requestStarted(_request) {\n markAsBusy(this.element);\n }\n requestPreventedHandlingResponse(_request, _response) {\n this.resolveVisitPromise();\n }\n async requestSucceededWithResponse(request, response) {\n await this.loadResponse(response);\n this.resolveVisitPromise();\n }\n async requestFailedWithResponse(request, response) {\n await this.loadResponse(response);\n this.resolveVisitPromise();\n }\n requestErrored(request, error) {\n console.error(error);\n this.resolveVisitPromise();\n }\n requestFinished(_request) {\n clearBusyState(this.element);\n }\n formSubmissionStarted({ formElement }) {\n markAsBusy(formElement, this.findFrameElement(formElement));\n }\n formSubmissionSucceededWithResponse(formSubmission, response) {\n const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);\n frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);\n frame.delegate.loadResponse(response);\n if (!formSubmission.isSafe) {\n session.clearCache();\n }\n }\n formSubmissionFailedWithResponse(formSubmission, fetchResponse) {\n this.element.delegate.loadResponse(fetchResponse);\n session.clearCache();\n }\n formSubmissionErrored(formSubmission, error) {\n console.error(error);\n }\n formSubmissionFinished({ formElement }) {\n clearBusyState(formElement, this.findFrameElement(formElement));\n }\n allowsImmediateRender({ element: newFrame }, options) {\n const event = dispatch(\"turbo:before-frame-render\", {\n target: this.element,\n detail: Object.assign({ newFrame }, options),\n cancelable: true,\n });\n const { defaultPrevented, detail: { render }, } = event;\n if (this.view.renderer && render) {\n this.view.renderer.renderElement = render;\n }\n return !defaultPrevented;\n }\n viewRenderedSnapshot(_snapshot, _isPreview) { }\n preloadOnLoadLinksForView(element) {\n session.preloadOnLoadLinksForView(element);\n }\n viewInvalidated() { }\n willRenderFrame(currentElement, _newElement) {\n this.previousFrameElement = currentElement.cloneNode(true);\n }\n async loadFrameResponse(fetchResponse, document) {\n const newFrameElement = await this.extractForeignFrameElement(document.body);\n if (newFrameElement) {\n const snapshot = new Snapshot(newFrameElement);\n const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);\n if (this.view.renderPromise)\n await this.view.renderPromise;\n this.changeHistory();\n await this.view.render(renderer);\n this.complete = true;\n session.frameRendered(fetchResponse, this.element);\n session.frameLoaded(this.element);\n this.fetchResponseLoaded(fetchResponse);\n }\n else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {\n this.handleFrameMissingFromResponse(fetchResponse);\n }\n }\n async visit(url) {\n var _a;\n const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);\n (_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();\n this.currentFetchRequest = request;\n return new Promise((resolve) => {\n this.resolveVisitPromise = () => {\n this.resolveVisitPromise = () => { };\n this.currentFetchRequest = null;\n resolve();\n };\n request.perform();\n });\n }\n navigateFrame(element, url, submitter) {\n const frame = this.findFrameElement(element, submitter);\n frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);\n this.withCurrentNavigationElement(element, () => {\n frame.src = url;\n });\n }\n proposeVisitIfNavigatedWithAction(frame, element, submitter) {\n this.action = getVisitAction(submitter, element, frame);\n if (this.action) {\n const pageSnapshot = PageSnapshot.fromElement(frame).clone();\n const { visitCachedSnapshot } = frame.delegate;\n frame.delegate.fetchResponseLoaded = (fetchResponse) => {\n if (frame.src) {\n const { statusCode, redirected } = fetchResponse;\n const responseHTML = frame.ownerDocument.documentElement.outerHTML;\n const response = { statusCode, redirected, responseHTML };\n const options = {\n response,\n visitCachedSnapshot,\n willRender: false,\n updateHistory: false,\n restorationIdentifier: this.restorationIdentifier,\n snapshot: pageSnapshot,\n };\n if (this.action)\n options.action = this.action;\n session.visit(frame.src, options);\n }\n };\n }\n }\n changeHistory() {\n if (this.action) {\n const method = getHistoryMethodForAction(this.action);\n session.history.update(method, expandURL(this.element.src || \"\"), this.restorationIdentifier);\n }\n }\n async handleUnvisitableFrameResponse(fetchResponse) {\n console.warn(`The response (${fetchResponse.statusCode}) from is performing a full page visit due to turbo-visit-control.`);\n await this.visitResponse(fetchResponse.response);\n }\n willHandleFrameMissingFromResponse(fetchResponse) {\n this.element.setAttribute(\"complete\", \"\");\n const response = fetchResponse.response;\n const visit = async (url, options = {}) => {\n if (url instanceof Response) {\n this.visitResponse(url);\n }\n else {\n session.visit(url, options);\n }\n };\n const event = dispatch(\"turbo:frame-missing\", {\n target: this.element,\n detail: { response, visit },\n cancelable: true,\n });\n return !event.defaultPrevented;\n }\n handleFrameMissingFromResponse(fetchResponse) {\n this.view.missing();\n this.throwFrameMissingError(fetchResponse);\n }\n throwFrameMissingError(fetchResponse) {\n const message = `The response (${fetchResponse.statusCode}) did not contain the expected and will be ignored. To perform a full page visit instead, set turbo-visit-control to reload.`;\n throw new TurboFrameMissingError(message);\n }\n async visitResponse(response) {\n const wrapped = new FetchResponse(response);\n const responseHTML = await wrapped.responseHTML;\n const { location, redirected, statusCode } = wrapped;\n return session.visit(location, { response: { redirected, statusCode, responseHTML } });\n }\n findFrameElement(element, submitter) {\n var _a;\n const id = getAttribute(\"data-turbo-frame\", submitter, element) || this.element.getAttribute(\"target\");\n return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;\n }\n async extractForeignFrameElement(container) {\n let element;\n const id = CSS.escape(this.id);\n try {\n element = activateElement(container.querySelector(`turbo-frame#${id}`), this.sourceURL);\n if (element) {\n return element;\n }\n element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`), this.sourceURL);\n if (element) {\n await element.loaded;\n return await this.extractForeignFrameElement(element);\n }\n }\n catch (error) {\n console.error(error);\n return new FrameElement();\n }\n return null;\n }\n formActionIsVisitable(form, submitter) {\n const action = getAction(form, submitter);\n return locationIsVisitable(expandURL(action), this.rootLocation);\n }\n shouldInterceptNavigation(element, submitter) {\n const id = getAttribute(\"data-turbo-frame\", submitter, element) || this.element.getAttribute(\"target\");\n if (element instanceof HTMLFormElement && !this.formActionIsVisitable(element, submitter)) {\n return false;\n }\n if (!this.enabled || id == \"_top\") {\n return false;\n }\n if (id) {\n const frameElement = getFrameElementById(id);\n if (frameElement) {\n return !frameElement.disabled;\n }\n }\n if (!session.elementIsNavigatable(element)) {\n return false;\n }\n if (submitter && !session.elementIsNavigatable(submitter)) {\n return false;\n }\n return true;\n }\n get id() {\n return this.element.id;\n }\n get enabled() {\n return !this.element.disabled;\n }\n get sourceURL() {\n if (this.element.src) {\n return this.element.src;\n }\n }\n set sourceURL(sourceURL) {\n this.ignoringChangesToAttribute(\"src\", () => {\n this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;\n });\n }\n get loadingStyle() {\n return this.element.loading;\n }\n get isLoading() {\n return this.formSubmission !== undefined || this.resolveVisitPromise() !== undefined;\n }\n get complete() {\n return this.element.hasAttribute(\"complete\");\n }\n set complete(value) {\n this.ignoringChangesToAttribute(\"complete\", () => {\n if (value) {\n this.element.setAttribute(\"complete\", \"\");\n }\n else {\n this.element.removeAttribute(\"complete\");\n }\n });\n }\n get isActive() {\n return this.element.isActive && this.connected;\n }\n get rootLocation() {\n var _a;\n const meta = this.element.ownerDocument.querySelector(`meta[name=\"turbo-root\"]`);\n const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : \"/\";\n return expandURL(root);\n }\n isIgnoringChangesTo(attributeName) {\n return this.ignoredAttributes.has(attributeName);\n }\n ignoringChangesToAttribute(attributeName, callback) {\n this.ignoredAttributes.add(attributeName);\n callback();\n this.ignoredAttributes.delete(attributeName);\n }\n withCurrentNavigationElement(element, callback) {\n this.currentNavigationElement = element;\n callback();\n delete this.currentNavigationElement;\n }\n}\nfunction getFrameElementById(id) {\n if (id != null) {\n const element = document.getElementById(id);\n if (element instanceof FrameElement) {\n return element;\n }\n }\n}\nfunction activateElement(element, currentURL) {\n if (element) {\n const src = element.getAttribute(\"src\");\n if (src != null && currentURL != null && urlsAreEqual(src, currentURL)) {\n throw new Error(`Matching element has a source URL which references itself`);\n }\n if (element.ownerDocument !== document) {\n element = document.importNode(element, true);\n }\n if (element instanceof FrameElement) {\n element.connectedCallback();\n element.disconnectedCallback();\n return element;\n }\n }\n}\n\nclass StreamElement extends HTMLElement {\n static async renderElement(newElement) {\n await newElement.performAction();\n }\n async connectedCallback() {\n try {\n await this.render();\n }\n catch (error) {\n console.error(error);\n }\n finally {\n this.disconnect();\n }\n }\n async render() {\n var _a;\n return ((_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {\n const event = this.beforeRenderEvent;\n if (this.dispatchEvent(event)) {\n await nextAnimationFrame();\n await event.detail.render(this);\n }\n })()));\n }\n disconnect() {\n try {\n this.remove();\n }\n catch (_a) { }\n }\n removeDuplicateTargetChildren() {\n this.duplicateChildren.forEach((c) => c.remove());\n }\n get duplicateChildren() {\n var _a;\n const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id);\n const newChildrenIds = [...(((_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children) || [])].filter((c) => !!c.id).map((c) => c.id);\n return existingChildren.filter((c) => newChildrenIds.includes(c.id));\n }\n get performAction() {\n if (this.action) {\n const actionFunction = StreamActions[this.action];\n if (actionFunction) {\n return actionFunction;\n }\n this.raise(\"unknown action\");\n }\n this.raise(\"action attribute is missing\");\n }\n get targetElements() {\n if (this.target) {\n return this.targetElementsById;\n }\n else if (this.targets) {\n return this.targetElementsByQuery;\n }\n else {\n this.raise(\"target or targets attribute is missing\");\n }\n }\n get templateContent() {\n return this.templateElement.content.cloneNode(true);\n }\n get templateElement() {\n if (this.firstElementChild === null) {\n const template = this.ownerDocument.createElement(\"template\");\n this.appendChild(template);\n return template;\n }\n else if (this.firstElementChild instanceof HTMLTemplateElement) {\n return this.firstElementChild;\n }\n this.raise(\"first child element must be a