{
  "version": 3,
  "sources": ["../src/front-end-module/libs/show-overlay.mjs", "../src/front-end-module/ui.mjs", "../node_modules/engine.io-parser/build/esm/commons.js", "../node_modules/engine.io-parser/build/esm/encodePacket.browser.js", "../node_modules/engine.io-parser/build/esm/contrib/base64-arraybuffer.js", "../node_modules/engine.io-parser/build/esm/decodePacket.browser.js", "../node_modules/engine.io-parser/build/esm/index.js", "../node_modules/@socket.io/component-emitter/lib/esm/index.js", "../node_modules/engine.io-client/build/esm/globals.js", "../node_modules/engine.io-client/build/esm/util.js", "../node_modules/engine.io-client/build/esm/contrib/parseqs.js", "../node_modules/engine.io-client/build/esm/transport.js", "../node_modules/engine.io-client/build/esm/transports/polling.js", "../node_modules/engine.io-client/build/esm/contrib/has-cors.js", "../node_modules/engine.io-client/build/esm/transports/polling-xhr.js", "../node_modules/engine.io-client/build/esm/transports/websocket.js", "../node_modules/engine.io-client/build/esm/transports/webtransport.js", "../node_modules/engine.io-client/build/esm/transports/index.js", "../node_modules/engine.io-client/build/esm/contrib/parseuri.js", "../node_modules/engine.io-client/build/esm/socket.js", "../node_modules/engine.io-client/build/esm/index.js", "../node_modules/socket.io-client/build/esm/url.js", "../node_modules/socket.io-parser/build/esm/index.js", "../node_modules/socket.io-parser/build/esm/is-binary.js", "../node_modules/socket.io-parser/build/esm/binary.js", "../node_modules/socket.io-client/build/esm/on.js", "../node_modules/socket.io-client/build/esm/socket.js", "../node_modules/socket.io-client/build/esm/contrib/backo2.js", "../node_modules/socket.io-client/build/esm/manager.js", "../node_modules/socket.io-client/build/esm/index.js", "../src/components/ti-base-component.mjs", "../src/components/uib-var.mjs", "../src/components/uib-meta.mjs", "../src/components/apply-template.mjs", "../src/components/uib-control.mjs", "../src/front-end-module/reactive.mjs", "../src/front-end-module/libs/format-date-time.mjs", "../src/front-end-module/uibuilder.module.mjs", "../src/front-end-module/experimental.mjs"],
  "sourcesContent": ["/**\n * @description Overlay window for displaying messages and notifications.\n * Included in the UI module and from there into the main uibuilder module.\n * @license Apache-2.0\n * @author Julian Knight (Totally Information)\n * @copyright (c) 2025-2025 Julian Knight (Totally Information)\n */\n\n/** Creates and displays an overlay window with customizable content and behavior\n * @param {object} options - Configuration options for the overlay\n *   @param {string} [options.content] - Main content (text or HTML) to display\n *   @param {string} [options.title] - Optional title above the main content\n *   @param {string} [options.icon] - Optional icon to display left of title (HTML or text)\n *   @param {string} [options.type] - Overlay type: 'success', 'info', 'warning', or 'error'\n *   @param {boolean} [options.showDismiss] - Whether to show dismiss button (auto-determined if not set)\n *   @param {number|null} [options.autoClose] - Auto-close delay in seconds (null for no auto-close)\n *   @param {boolean} [options.time] - Show timestamp in overlay (default: true)\n * @returns {object} Object with close() method to manually close the overlay\n */\nexport function showOverlay(options = {}) {\n    const {\n        content = '',\n        title = '',\n        icon = '',\n        type = 'info',\n        showDismiss,\n        autoClose = 5,\n        time = true,\n    } = options\n\n    const overlayContainerId = 'uib-info-overlay'\n\n    // Get or create the main overlay container\n    let overlayContainer = document.getElementById(overlayContainerId)\n    if (!overlayContainer) {\n        overlayContainer = document.createElement('div')\n        overlayContainer.id = overlayContainerId\n        document.body.appendChild(overlayContainer)\n        console.log('>> SHOW OVERLAY >>', options, document.getElementById(overlayContainerId))\n    }\n\n    // Generate unique ID for this overlay entry\n    const entryId = `overlay-entry-${Date.now()}-${Math.random().toString(36)\n        .substr(2, 9)}`\n\n    // Create individual overlay entry\n    const overlayEntry = document.createElement('div')\n    overlayEntry.id = entryId\n    overlayEntry.style.marginBottom = '0.5rem'\n\n    // Define type-specific styles\n    const typeStyles = {\n        info: {\n            iconDefault: '\u2139\uFE0F',\n            titleDefault: 'Information',\n            color: 'hsl(188.2deg 77.78% 40.59%)',\n        },\n        success: {\n            iconDefault: '\u2705',\n            titleDefault: 'Success',\n            color: 'hsl(133.7deg 61.35% 40.59%)',\n        },\n        warning: {\n            iconDefault: '\u26A0\uFE0F',\n            titleDefault: 'Warning',\n            color: 'hsl(35.19deg 84.38% 62.35%)',\n        },\n        error: {\n            iconDefault: '\u274C',\n            titleDefault: 'Error',\n            color: 'hsl(2.74deg 92.59% 62.94%)',\n        },\n    }\n\n    // @ts-ignore\n    const currentTypeStyle = typeStyles[type] || typeStyles.info\n\n    // Determine if dismiss button should be shown\n    const shouldShowDismiss = showDismiss !== undefined ? showDismiss : (autoClose === null)\n\n    // Create content HTML\n    const iconHtml = icon || currentTypeStyle.iconDefault\n    const titleText = title || currentTypeStyle.titleDefault\n\n    // Generate timestamp if time option is enabled\n    let timeHtml = ''\n    if (time) {\n        const now = new Date()\n        const year = now.getFullYear()\n        const month = String(now.getMonth() + 1).padStart(2, '0')\n        const day = String(now.getDate()).padStart(2, '0')\n        const hours = String(now.getHours()).padStart(2, '0')\n        const minutes = String(now.getMinutes()).padStart(2, '0')\n        const seconds = String(now.getSeconds()).padStart(2, '0')\n        const timestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`\n        timeHtml = `<div class=\"uib-overlay-time\" style=\"font-size: 0.8em; color: var(--text3, #999); margin-left: auto; margin-right: ${shouldShowDismiss ? '0.5rem' : '0'};\">${timestamp}</div>`\n    }\n\n    overlayEntry.innerHTML = /* html */ `\n        <div class=\"uib-overlay-entry\" style=\"--callout-color:${currentTypeStyle.color};\">\n            <div class=\"uib-overlay-header\">\n                <div class=\"uib-overlay-icon\">${iconHtml}</div>\n                <div class=\"uib-overlay-title\">${titleText}</div>\n                ${timeHtml}\n                ${shouldShowDismiss\n                    ? `<button class=\"uib-overlay-dismiss\" data-entry-id=\"${entryId}\" title=\"Close\">\u00D7</button>`\n                    : ''}\n            </div>\n            <div class=\"uib-overlay-content\">\n                ${content}\n            </div>\n        </div>\n    `\n\n    // Add to overlay container at the top, sliding existing entries down\n    if (overlayContainer.children.length > 0) {\n        // Insert new entry at the top\n        overlayContainer.insertBefore(overlayEntry, overlayContainer.firstChild)\n    } else {\n        // First entry, just add it normally\n        overlayContainer.appendChild(overlayEntry)\n    }\n\n    // Close function for this specific entry\n    const closeOverlayEntry = () => {\n        const entry = document.getElementById(entryId)\n        if (!entry) return\n\n        entry.style.animation = 'slideOut 0.3s ease-in'\n        setTimeout(() => {\n            if (entry.parentNode) {\n                entry.remove()\n                // Remove the main container if no entries remain\n                // const container = document.getElementById(overlayContainerId)\n                // if (container && container.children.length === 0) {\n                //     container.remove()\n                // }\n            }\n        }, 300)\n    }\n\n    // Add dismiss button event listener\n    const dismissBtn = overlayEntry.querySelector('.uib-overlay-dismiss')\n    if (dismissBtn) {\n        dismissBtn.addEventListener('click', closeOverlayEntry)\n    }\n\n    // Set up auto-close if specified\n    let autoCloseTimer = null\n    if (autoClose !== null && autoClose > 0) {\n        autoCloseTimer = setTimeout(closeOverlayEntry, autoClose * 1000)\n    }\n\n    // Return control object\n    return {\n        close: () => {\n            if (autoCloseTimer) {\n                clearTimeout(autoCloseTimer)\n            }\n            closeOverlayEntry()\n        },\n        id: entryId,\n    }\n}\n\nexport default showOverlay\n", "// @ts-nocheck\n/* Creates HTML UI's based on a standardised data input.\n  Works stand-alone, with uibuilder or with Node.js/jsdom.\n  See: https://totallyinformation.github.io/node-red-contrib-uibuilder/#/client-docs/config-driven-ui\n\n  Author: Julian Knight (Totally Information), March 2023\n\n  License: Apache 2.0\n  Copyright (c) 2022-2025 Julian Knight (Totally Information)\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n */\n\n// Namespaces - See https://stackoverflow.com/a/52572048/1309986\n// const NAMESPACES = {\n//     svg: 'http://www.w3.org/2000/svg',\n//     html: 'http://www.w3.org/1999/xhtml',\n//     xml: 'http://www.w3.org/XML/1998/namespace',\n//     xlink: 'http://www.w3.org/1999/xlink',\n//     xmlns: 'http://www.w3.org/2000/xmlns/' // sic for the final slash...\n// }\n\nimport { showOverlay } from './libs/show-overlay.mjs'\n\nconst Ui = class Ui {\n    // #region --- Class variables ---\n    version = '7.7.0-src'\n\n    // List of tags and attributes not in sanitise defaults but allowed in uibuilder.\n    sanitiseExtraTags = ['uib-var']\n    sanitiseExtraAttribs = ['variable', 'report', 'undefined']\n\n    /** DOMPurify custom element handling options - allows all valid custom elements (hyphenated tags)\n     * @type {{tagNameCheck: RegExp, attributeNameCheck: RegExp, allowCustomizedBuiltInElements: boolean}}\n     */\n    sanitiseCustomElementHandling = {\n        tagNameCheck: /^[a-z][a-z0-9]*-[a-z0-9-]*$/,\n        attributeNameCheck: /^[a-z_][\\w.-]*$/i,\n        allowCustomizedBuiltInElements: false,\n    }\n\n    /** Reference to DOM window - must be passed in the constructor\n     * Allows for use of this library/class with `jsdom` in Node.JS as well as the browser.\n     * @type {Window}\n     */\n    static win\n\n    /** Reference to the DOM top-level window.document for convenience - set in constructor @type {Document} */\n    static doc\n\n    /** Log function - passed in constructor or will be a dummy function\n     * @type {Function}\n     */\n    static log\n\n    /** Options for Markdown-IT if available (set in constructor) */\n    static mdOpts\n    /** Reference to pre-loaded Markdown-IT library */\n    static md\n    /** Optional Markdown-IT Plugins */\n    ui_md_plugins\n    // #endregion --- class variables ---\n\n    /** Called when `new Ui(...)` is called\n     * @param {globalThis} win Either the browser global window or jsdom dom.window\n     * @param {Function} [extLog] A function that returns a function for logging\n     * @param {Function} [jsonHighlight] A function that returns a highlighted HTML of JSON input\n     */\n    constructor(win, extLog, jsonHighlight) {\n        // window must be passed in as an arg to the constructor\n        // Should either be the global window for a browser or `dom.window` for jsdom in Node.js\n        // @ts-ignore\n        if (win) Ui.win = win\n        else {\n            // Ui.log(0, 'Ui:constructor', 'Current environment does not include `window`, UI functions cannot be used.')()\n            // return\n            throw new Error('Ui:constructor. Current environment does not include `window`, UI functions cannot be used.')\n        }\n\n        // For convenience\n        Ui.doc = Ui.win.document\n\n        // If a suitable function not passed in, create a dummy one\n        if (extLog) Ui.log = extLog\n        else Ui.log = function() { return function() {} } // eslint-disable-line @stylistic/max-statements-per-line\n\n        // If a JSON HTML highlighting function passed then use it, else a dummy fn\n        if (jsonHighlight) this.syntaxHighlight = jsonHighlight\n        else this.syntaxHighlight = function() {}\n\n        // If Markdown-IT pre-loaded, then configure it now\n        if (Ui.win['markdownit']) {\n            Ui.mdOpts = {\n                html: true,\n                xhtmlOut: false,\n                linkify: true,\n                _highlight: true,\n                _strict: false,\n                _view: 'html',\n                langPrefix: 'language-',\n                // NB: the highlightjs (hljs) library must be loaded before markdown-it for this to work\n                highlight: function(str, lang) {\n                    // https://highlightjs.org\n                    if (lang && window['hljs'] && window['hljs'].getLanguage(lang)) {\n                        try {\n                            return `<pre class=\"\">\n                                    <code class=\"hljs border\">${window['hljs'].highlight(str, { language: lang, ignoreIllegals: true, }).value}</code></pre>`\n                        } finally { } // eslint-disable-line no-empty\n                    }\n                    return `<pre class=\"hljs border\"><code>${Ui.md.utils.escapeHtml(str).trim()}</code></pre>`\n                },\n            }\n            Ui.md = Ui.win['markdownit'](Ui.mdOpts)\n        }\n    }\n\n    // #region ---- Internal Methods ----\n\n    _markDownIt() {\n        // If Markdown-IT pre-loaded, then configure it now\n        if (!Ui.win['markdownit']) return\n\n        // If plugins not yet defined, check if uibuilder has set them\n        if (!this.ui_md_plugins && Ui.win['uibuilder'] && Ui.win['uibuilder'].ui_md_plugins) this.ui_md_plugins = Ui.win['uibuilder'].ui_md_plugins\n\n        Ui.mdOpts = {\n            html: true,\n            xhtmlOut: false,\n            linkify: true,\n            _highlight: true,\n            _strict: false,\n            _view: 'html',\n            langPrefix: 'language-',\n            // NB: the highlightjs (hljs) library must be loaded before markdown-it for this to work\n            highlight: function(str, lang) {\n                if (window['hljs']) {\n                    if (lang && window['hljs'].getLanguage(lang)) {\n                        try {\n                            return `<pre><code class=\"hljs border language-${lang}\" data-language=\"${lang}\" title=\"Source language: '${lang}'\">${window['hljs'].highlight(str, { language: lang, ignoreIllegals: true, }).value}</code></pre>`\n                        } finally { } // eslint-disable-line no-empty\n                    } else {\n                        try {\n                            const high = window['hljs'].highlightAuto(str)\n                            return `<pre><code class=\"hljs border language-${high.language}\" data-language=\"${high.language}\" title=\"Source language estimated by HighlightJS: '${high.language}'\">${high.value}</code></pre>`\n                        } finally { } // eslint-disable-line no-empty\n                    }\n                }\n                return `<pre><code class=\"border\">${Ui.md.utils.escapeHtml(str).trim()}</code></pre>`\n            },\n        }\n        Ui.md = Ui.win['markdownit'](Ui.mdOpts)\n        // Ui.md.use(Ui.win.markdownitTaskLists, {enabled: true})\n        if (this.ui_md_plugins) {\n            if (!Array.isArray(this.ui_md_plugins)) {\n                Ui.log('error', 'Ui:_markDownIt:plugins', 'Could not load plugins, ui_md_plugins is not an array')()\n                return\n            }\n            this.ui_md_plugins.forEach( (plugin) => {\n                if (typeof plugin === 'string') {\n                    Ui.md.use(Ui.win[plugin])\n                } else {\n                    const name = Object.keys(plugin)[0]\n                    Ui.md.use(Ui.win[name], plugin[name])\n                }\n            })\n        }\n    }\n\n    /** Show a browser notification if the browser and the user allows it\n     * @param {object} config Notification config data\n     * @returns {Promise} Resolves on close or click event, returns the event.\n     */\n    _showNotification(config) {\n        if ( config.topic && !config.title ) config.title = config.topic\n        if ( !config.title ) config.title = 'uibuilder notification'\n        if ( config.payload && !config.body ) config.body = config.payload\n        if ( !config.body ) config.body = ' No message given.'\n        // Wrap in try/catch since Chrome Android may throw an error\n        try {\n            const notify = new Notification(config.title, config)\n            return new Promise( (resolve, reject) => {\n                // Doesn't ever seem to fire (at least in Chromium)\n                notify.addEventListener('close', (ev) => {\n                    // @ts-ignore\n                    ev.currentTarget.userAction = 'close'\n                    resolve(ev)\n                })\n                notify.addEventListener('click', (ev) => {\n                    // @ts-ignore\n                    ev.currentTarget.userAction = 'click'\n                    resolve(ev)\n                })\n                notify.addEventListener('error', (ev) => {\n                    // @ts-ignore\n                    ev.currentTarget.userAction = 'error'\n                    reject(ev)\n                })\n            })\n        } catch (e) {\n            return Promise.reject(new Error('Browser refused to create a Notification'))\n        }\n    }\n\n    // Vue dynamic inserts Don't really work ...\n    // _uiAddVue(ui, isRecurse) {\n\n    //     // must be Vue\n    //     // must have only 1 root element\n    //     const compToAdd = ui.components[0]\n    //     const newEl = Ui.doc.createElement(compToAdd.type)\n\n    //     if (!compToAdd.slot && ui.payload) compToAdd.slot = ui.payload\n    //     this._uiComposeComponent(newEl, compToAdd)\n\n    //     // If nested components, go again - but don't pass payload to sub-components\n    //     if (compToAdd.components) {\n    //         this._uiExtendEl(newEl, compToAdd.components)\n    //     }\n\n    //     console.log('MAGIC: ', this.magick, newEl, newEl.outerHTML)()\n    //     this.set('magick', newEl.outerHTML)\n\n    //     // if (compToAdd.id) newEl.setAttribute('ref', compToAdd.id)\n    //     // if (elParent.id) newEl.setAttribute('data-parent', elParent.id)\n    // }\n\n    // TODO Add check if ID already exists\n    // TODO Allow single add without using components array\n    /** Handle incoming msg._ui add requests\n     * @param {*} ui Standardised msg._ui property object. Note that payload and topic are appended to this object\n     * @param {boolean} isRecurse Is this a recursive call?\n     */\n    _uiAdd(ui, isRecurse) {\n        Ui.log('trace', 'Ui:_uiManager:add', 'Starting _uiAdd')()\n\n        // Vue dynamic inserts Don't really work ...\n        // if (this.#isVue && !isRecurse) {\n        //     this._uiAddVue(ui, false)\n        //     return\n        // }\n\n        ui.components.forEach((compToAdd, i) => {\n            Ui.log('trace', `Ui:_uiAdd:components-forEach:${i}`, 'Component to add: ', compToAdd)()\n\n            /** @type {*} Create the new component - some kind of HTML element */\n            let newEl\n            switch (compToAdd.type) {\n                // If trying to insert raw html, wrap in a div\n                case 'html': {\n                    compToAdd.ns = 'html'\n                    newEl = Ui.doc.createElement('div')\n                    break\n                }\n\n                // If trying to insert raw svg, need to create in namespace\n                case 'svg': {\n                    compToAdd.ns = 'svg'\n                    newEl = Ui.doc.createElementNS('http://www.w3.org/2000/svg', 'svg')\n                    break\n                }\n\n                default: {\n                    compToAdd.ns = 'dom'\n                    newEl = Ui.doc.createElement(compToAdd.type)\n                    break\n                }\n            }\n\n            if (!compToAdd.slot && ui.payload) compToAdd.slot = ui.payload\n\n            // const parser = new DOMParser()\n            // const newDoc = parser.parseFromString(compToAdd.slot, 'text/html')\n            // console.log(compToAdd, newDoc.body)()\n\n            this._uiComposeComponent(newEl, compToAdd)\n\n            /** @type {HTMLElement} Where to add the new element? */\n            let elParent\n            if (compToAdd.parentEl) {\n                elParent = compToAdd.parentEl\n            } else if (ui.parentEl) {\n                elParent = ui.parentEl\n            } else if (compToAdd.parent) {\n                elParent = Ui.doc.querySelector(compToAdd.parent)\n            } else if (ui.parent) {\n                elParent = Ui.doc.querySelector(ui.parent)\n            }\n            if (!elParent) {\n                Ui.log('info', 'Ui:_uiAdd', 'No parent found, adding to body')()\n                elParent = Ui.doc.querySelector('body')\n            }\n\n            if (compToAdd.position && compToAdd.position === 'first') {\n                // Insert new el before the first child of the parent. Ref: https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore#example_3\n                elParent.insertBefore(newEl, elParent.firstChild)\n            } else if (compToAdd.position && Number.isInteger(Number(compToAdd.position))) {\n                elParent.insertBefore(newEl, elParent.children[compToAdd.position])\n            } else {\n                // Append to the required parent\n                elParent.appendChild(newEl)\n            }\n\n            // If nested components, go again - but don't pass payload to sub-components\n            if (compToAdd.components) {\n                // this._uiAdd({\n                //     method: ui.method,\n                //     parentEl: newEl,\n                //     components: compToAdd.components,\n                // }, true)\n                this._uiExtendEl(newEl, compToAdd.components, compToAdd.ns)\n            }\n        })\n    } // --- end of _uiAdd ---\n\n    /** Enhance an HTML element that is being composed with ui data\n     *  such as ID, attribs, event handlers, custom props, etc.\n     * @param {*} el HTML Element to enhance\n     * @param {*} comp Individual uibuilder ui component spec\n     */\n    _uiComposeComponent(el, comp) {\n        // Add attributes\n        if (comp.attributes) {\n            Object.keys(comp.attributes).forEach((attrib) => {\n                if (attrib === 'class' && Array.isArray(comp.attributes[attrib])) comp.attributes[attrib].join(' ')\n\n                Ui.log('trace', '_uiComposeComponent:attributes-forEach', `Attribute: '${attrib}', value: '${comp.attributes[attrib]}'`)()\n\n                // For values, set the actual value as well since the attrib only changes the DEFAULT value\n                if (attrib === 'value') el.value = comp.attributes[attrib]\n\n                if (attrib.startsWith('xlink:')) el.setAttributeNS('http://www.w3.org/1999/xlink', attrib, comp.attributes[attrib])\n                else el.setAttribute(attrib, comp.attributes[attrib])\n            })\n        }\n\n        // ID if set\n        if (comp.id) el.setAttribute('id', comp.id)\n\n        // If an SVG tag, ensure we have the appropriate namespaces added\n        if (comp.type === 'svg') {\n            el.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg')\n            el.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink')\n        }\n\n        // Add event handlers\n        if (comp.events) {\n            Object.keys(comp.events).forEach((type) => {\n                // @ts-ignore  I'm forever getting this wrong!\n                if (type.toLowerCase === 'onclick') type = 'click'\n                // Add the event listener\n                try {\n                    el.addEventListener(type, (evt) => {\n                        // Use new Function to ensure that esbuild works: https://esbuild.github.io/content-types/#direct-eval\n                        (new Function('evt', `${comp.events[type]}(evt)`))(evt)\n                    })\n                    // newEl.setAttribute( 'onClick', `${comp.events[type]}()` )\n                } catch (err) {\n                    Ui.log('error', 'Ui:_uiComposeComponent', `Add event '${type}' for element '${comp.type}': Cannot add event handler. ${err.message}`)()\n                }\n            })\n        }\n\n        // Add custom properties to the dataset\n        if (comp.properties) {\n            Object.keys(comp.properties).forEach((prop) => {\n                // TODO break a.b into sub properties\n                el[prop] = comp.properties[prop]\n                // Auto-dispatch events if changing value or changed since DOM does not do this automatically\n                if (['value', 'checked'].includes(prop)) {\n                    el.dispatchEvent(new Event('input'))\n                    el.dispatchEvent(new Event('change'))\n                }\n            })\n        }\n\n        // #region Add Slot content to innerHTML\n        if (comp.slot) {\n            this.replaceSlot(el, comp.slot)\n        }\n        //#endregion\n\n        // TODO Add multi-slot capability (default slot must always be processed first as innerHTML is replaced)\n\n        // #region Add Slot Markdown content to innerHTML IF marked library is available\n        if (comp.slotMarkdown) {\n            this.replaceSlotMarkdown(el, comp)\n        }\n        //#endregion\n    }\n\n    /** Extend an HTML Element with appended elements using ui components\n     * NOTE: This fn follows a strict hierarchy of added components.\n     * @param {HTMLElement} parentEl The parent HTML Element we want to append to\n     * @param {*} components The ui component(s) we want to add\n     * @param {string} [ns] Optional. The namespace to use.\n     */\n    _uiExtendEl(parentEl, components, ns = '') {\n        components.forEach((compToAdd, i) => {\n            Ui.log('trace', `Ui:_uiExtendEl:components-forEach:${i}`, compToAdd)()\n\n            /** @type {HTMLElement} Create the new component */\n            let newEl\n\n            compToAdd.ns = ns\n\n            if (compToAdd.ns === 'html') {\n                newEl = parentEl\n                // newEl.outerHTML = compToAdd.slot\n                // parentEl.innerHTML = compToAdd.slot\n                this.replaceSlot(parentEl, compToAdd.slot)\n            } else if (compToAdd.ns === 'svg') {\n                newEl = Ui.doc.createElementNS('http://www.w3.org/2000/svg', compToAdd.type)\n                // Updates newEl\n                this._uiComposeComponent(newEl, compToAdd)\n                parentEl.appendChild(newEl)\n            } else {\n                newEl = Ui.doc.createElement(compToAdd.type === 'html' ? 'div' : compToAdd.type)\n                // Updates newEl\n                this._uiComposeComponent(newEl, compToAdd)\n                parentEl.appendChild(newEl)\n            }\n\n            // If nested components, go again - but don't pass payload to sub-components\n            if (compToAdd.components) {\n                this._uiExtendEl(newEl, compToAdd.components, compToAdd.ns)\n            }\n        })\n    }\n\n    // TODO Add more error handling and parameter validation\n    /** Handle incoming _ui load requests\n     * Can load JavaScript modules, JavaScript scripts and CSS.\n     * @param {*} ui Standardised msg._ui property object. Note that payload and topic are appended to this object\n     */\n    _uiLoad(ui) {\n        // Self-loading ECMA Modules (e.g. web components)\n        if (ui.components) {\n            if (!Array.isArray(ui.components)) ui.components = [ui.components]\n\n            ui.components.forEach(async (component) => {\n                // NOTE: This happens asynchronously but we don't wait\n                import(component)\n            })\n        }\n        // Remote Scripts\n        if (ui.srcScripts) {\n            if (!Array.isArray(ui.srcScripts)) ui.srcScripts = [ui.srcScripts]\n\n            ui.srcScripts.forEach((script) => {\n                this.loadScriptSrc(script)\n            })\n        }\n        // Scripts passed as text\n        if (ui.txtScripts) {\n            if (!Array.isArray(ui.txtScripts)) ui.txtScripts = [ui.txtScripts]\n\n            this.loadScriptTxt(ui.txtScripts.join('\\n'))\n        }\n        // Remote Stylesheets\n        if (ui.srcStyles) {\n            if (!Array.isArray(ui.srcStyles)) ui.srcStyles = [ui.srcStyles]\n\n            ui.srcStyles.forEach((sheet) => {\n                this.loadStyleSrc(sheet)\n            })\n        }\n        // Styles passed as text\n        if (ui.txtStyles) {\n            if (!Array.isArray(ui.txtStyles)) ui.txtStyles = [ui.txtStyles]\n\n            this.loadStyleTxt(ui.txtStyles.join('\\n'))\n        }\n    } // --- end of _uiLoad ---\n\n    /** Handle incoming _ui messages and loaded UI JSON files\n     * Called from start()\n     * @param {*} msg Standardised msg object containing a _ui property object\n     */\n    _uiManager(msg) {\n        if (!msg._ui) return\n\n        // Make sure that _ui is an array\n        if (!Array.isArray(msg._ui)) msg._ui = [msg._ui]\n\n        msg._ui.forEach((ui, i) => {\n            if (ui.mode && !ui.method) ui.method = ui.mode\n            if (!ui.method) {\n                Ui.log('error', 'Ui:_uiManager', `No method defined for msg._ui[${i}]. Ignoring. `, ui)()\n                return\n            }\n\n            ui.payload = msg.payload\n            ui.topic = msg.topic\n            switch (ui.method) {\n                case 'add': {\n                    this._uiAdd(ui, false)\n                    break\n                }\n\n                case 'remove': {\n                    this._uiRemove(ui, false)\n                    break\n                }\n\n                case 'removeAll': {\n                    this._uiRemove(ui, true)\n                    break\n                }\n\n                case 'replace': {\n                    this._uiReplace(ui)\n                    break\n                }\n\n                case 'update': {\n                    this._uiUpdate(ui)\n                    break\n                }\n\n                case 'load': {\n                    this._uiLoad(ui)\n                    break\n                }\n\n                case 'reload': {\n                    this._uiReload()\n                    break\n                }\n\n                case 'notify': {\n                    this.showDialog('notify', ui, msg)\n                    break\n                }\n\n                case 'alert': {\n                    this.showDialog('alert', ui, msg)\n                    break\n                }\n\n                default: {\n                    Ui.log('error', 'Ui:_uiManager', `Invalid msg._ui[${i}].method (${ui.method}). Ignoring`)()\n                    break\n                }\n            }\n        })\n    } // --- end of _uiManager ---\n\n    /** Handle a reload request */\n    _uiReload() {\n        Ui.log('trace', 'Ui:uiManager:reload', 'reloading')()\n        location.reload()\n    }\n\n    // TODO Add better tests for failures (see comments)\n    /** Handle incoming _ui remove requests\n     * @param {*} ui Standardised msg._ui property object. Note that payload and topic are appended to this object\n     * @param {boolean} all Optional, default=false. If true, will remove ALL found elements, otherwise only the 1st is removed\n     */\n    _uiRemove(ui, all = false) {\n        ui.components.forEach((compToRemove) => {\n            let els\n            if (all !== true) els = [Ui.doc.querySelector(compToRemove)]\n            else els = Ui.doc.querySelectorAll(compToRemove)\n\n            els.forEach((el) => {\n                try {\n                    el.remove()\n                } catch (err) {\n                    // Could not remove. Cannot read properties of null <= no need to report this one\n                    // Could not remove. Failed to execute 'querySelector' on 'Ui.doc': '##testbutton1' is not a valid selector\n                    Ui.log('trace', 'Ui:_uiRemove', `Could not remove. ${err.message}`)()\n                }\n            })\n        })\n    } // --- end of _uiRemove ---\n\n    /** Handle incoming _ui replace requests\n     * @param {*} ui Standardised msg._ui property object. Note that payload and topic are appended to this object\n     */\n    _uiReplace(ui) {\n        Ui.log('trace', 'Ui:_uiReplace', 'Starting')()\n\n        ui.components.forEach((compToReplace, /** @type {number} */ i) => {\n            Ui.log('trace', `Ui:_uiReplace:components-forEach:${i}`, 'Component to replace: ', compToReplace)()\n\n            /** @type {HTMLElement} */\n            let elToReplace\n\n            // Either the id, CSS selector, name or type (element type) must be given in order to identify the element to change. FIRST element matching is updated.\n            if (compToReplace.id) {\n                elToReplace = Ui.doc.getElementById(compToReplace.id) // .querySelector(`#${compToReplace.id}`)\n            } else if (compToReplace.selector || compToReplace.select) {\n                elToReplace = Ui.doc.querySelector(compToReplace.selector)\n            } else if (compToReplace.name) {\n                elToReplace = Ui.doc.querySelector(`[name=\"${compToReplace.name}\"]`)\n            } else if (compToReplace.type) {\n                elToReplace = Ui.doc.querySelector(compToReplace.type)\n            }\n\n            Ui.log('trace', `Ui:_uiReplace:components-forEach:${i}`, 'Element to replace: ', elToReplace)()\n\n            // Nothing was found so ADD the element instead\n            if (elToReplace === undefined || elToReplace === null) {\n                Ui.log('trace', `Ui:_uiReplace:components-forEach:${i}:noReplace`, 'Cannot find the DOM element. Adding instead.', compToReplace)()\n                this._uiAdd({ components: [compToReplace], }, false)\n                return\n            }\n\n            /** @type {*} Create the new component - some kind of HTML element */\n            let newEl\n            switch (compToReplace.type) {\n                // If trying to insert raw html, wrap in a div\n                case 'html': {\n                    compToReplace.ns = 'html'\n                    newEl = Ui.doc.createElement('div')\n                    break\n                }\n\n                // If trying to insert raw svg, need to create in namespace\n                case 'svg': {\n                    compToReplace.ns = 'svg'\n                    newEl = Ui.doc.createElementNS('http://www.w3.org/2000/svg', 'svg')\n                    break\n                }\n\n                default: {\n                    compToReplace.ns = 'dom'\n                    newEl = Ui.doc.createElement(compToReplace.type)\n                    break\n                }\n            }\n\n            // Updates the newEl and maybe the ui\n            this._uiComposeComponent(newEl, compToReplace)\n\n            // Replace the current element\n            elToReplace.replaceWith(newEl)\n\n            // If nested components, go again - but don't pass payload to sub-components\n            if (compToReplace.components) {\n                this._uiExtendEl(newEl, compToReplace.components, compToReplace.ns)\n            }\n        })\n    } // --- end of _uiReplace ---\n\n    // TODO Allow single add without using components array\n    // TODO Allow sub-components\n    // TODO Add multi-slot capability\n    /** Handle incoming _ui update requests\n     * @param {*} ui Standardised msg._ui property object. Note that payload and topic are appended to this object\n     */\n    _uiUpdate(ui) {\n        Ui.log('trace', 'UI:_uiUpdate:update', 'Starting _uiUpdate', ui)()\n\n        // We allow an update not to actually need to spec a component\n        if (!ui.components) ui.components = [Object.assign({}, ui)]\n\n        ui.components.forEach((compToUpd, i) => {\n            Ui.log('trace', '_uiUpdate:components-forEach', `Start loop #${i}`, compToUpd)()\n\n            /** @type {NodeListOf<Element>} */\n            let elToUpd\n\n            // If a parent element is passed, use that as the update target (only allowed internally)\n            // Otherwise either the id, CSS selector, name or type (element type) must be given in order to identify the element to change. ALL elements matching are updated.\n            if (compToUpd.parentEl) {\n                elToUpd = compToUpd.parentEl\n            } else if (compToUpd.id) {\n                // NB We don't use get by id because this way the code is simpler later on\n                elToUpd = Ui.doc.querySelectorAll(`#${compToUpd.id}`)\n            } else if (compToUpd.selector || compToUpd.select) {\n                elToUpd = Ui.doc.querySelectorAll(compToUpd.selector)\n            } else if (compToUpd.name) {\n                elToUpd = Ui.doc.querySelectorAll(`[name=\"${compToUpd.name}\"]`)\n            } else if (compToUpd.type) {\n                elToUpd = Ui.doc.querySelectorAll(compToUpd.type)\n            }\n\n            // @ts-ignore Nothing was found so give up\n            if (elToUpd === undefined || elToUpd.length < 1) {\n                Ui.log('warn', 'Ui:_uiManager:update', 'Cannot find the DOM element. Ignoring.', compToUpd)()\n                return\n            }\n\n            Ui.log('trace', '_uiUpdate:components-forEach', `Element(s) to update. Count: ${elToUpd.length}`, elToUpd)()\n\n            // If slot not specified but payload is, use the payload in the slot\n            if (!compToUpd.slot && compToUpd.payload) compToUpd.slot = compToUpd.payload\n\n            // Might have >1 element to update - so update them all\n            elToUpd.forEach((el, j) => {\n                Ui.log('trace', '_uiUpdate:components-forEach', `Updating element #${j}`, el)()\n                this._uiComposeComponent(el, compToUpd)\n                // Try to go down another level of nesting if needed\n                // ! NOT CONVINCED THIS ACTUALLY WORKS !\n                if (compToUpd.components) {\n                    Ui.log('trace', '_uiUpdate:nested-component', `Element #${j} - nested-component`, compToUpd, el)()\n                    const nc = { _ui: [], }\n                    compToUpd.components.forEach((nestedComp, k) => {\n                        const method = nestedComp.method || compToUpd.method || ui.method\n                        if (nestedComp.method) delete nestedComp.method\n                        if (!Array.isArray(nestedComp)) nestedComp = [nestedComp]\n                        // nestedComp.parentEl = el\n                        // nestedComp.components = [nestedComp]\n                        Ui.log('trace', '_uiUpdate:nested-component', `Element #${j} - nested-component #${k}`, nestedComp)()\n                        nc._ui.push( {\n                            method: method,\n                            parentEl: el,\n                            components: nestedComp,\n                        })\n                    })\n                    Ui.log('trace', '_uiUpdate:nested-component', `Element #${j} - nested-component new manager`, nc)()\n                    this._uiManager(nc)\n                }\n            })\n\n            // If nested components, apply to every found element - but don't pass payload to sub-components\n            // if (compToUpd.components) {\n            //     compToUpd.components.forEach((el, k) => {\n            //         Ui.log('trace', '_uiUpdate:nested-component', `Updating nested-component #${k}`, el)()\n            //         this._uiUpdate({\n            //             method: el.method || ui.method,\n            //             parentEl: el,\n            //             components: el.components,\n            //         })\n            //     })\n            // }\n        })\n    } // --- end of _uiUpdate ---\n\n    // #endregion ---- -------- ----\n\n    // #region ---- External Methods ----\n\n    /** Simplistic jQuery-like document CSS query selector, returns an HTML Element\n     * NOTE that this fn returns the element itself. Use $$ to get the properties of 1 or more elements.\n     * If the selected element is a <template>, returns the first child element.\n     * type {HTMLElement}\n     * @param {string} cssSelector A CSS Selector that identifies the element to return\n     * @param {\"el\"|\"text\"|\"html\"|\"attributes\"|\"attr\"} [output] Optional. What type of output to return. Defaults to \"el\", the DOM element reference\n     * @param {HTMLElement} [context] Optional. The context to search within. Defaults to the document. Must be a DOM element.\n     * @returns {HTMLElement|string|Array|null} Selected HTML DOM element, innerText, innerHTML, attribute list or null\n     */\n    $(cssSelector, output, context) {\n        if (!context) context = Ui.doc\n        if (!output) output = 'el'\n\n        // if context is not a valid htmlelement, return null\n        if (!context || !context.nodeType) {\n            Ui.log(1, 'Uib:$', `Invalid context element. Must be a valid HTML element.`, context)()\n            return null\n        }\n\n        /** @type {HTMLElement} Some kind of HTML element */\n        let el = (context).querySelector(cssSelector)\n\n        // if no element found or is not a valid htmlelement, return null\n        if (!el || !el.nodeType) {\n            Ui.log(1, 'Uib:$', `No element found or element is not an HTML element for CSS selector ${cssSelector}`)()\n            return null\n        }\n\n        if ( el.nodeName === 'TEMPLATE' ) {\n            el = el.content.firstElementChild\n            if (!el) {\n                Ui.log(0, 'Uib:$', `Template selected for CSS selector ${cssSelector} but it is empty`)()\n                return null\n            }\n        }\n\n        let out\n\n        try {\n            switch (output.toLowerCase()) {\n                case 'text': {\n                    out = el.innerText\n                    break\n                }\n\n                case 'html': {\n                    out = el.innerHTML\n                    break\n                }\n\n                case 'attr':\n                case 'attributes': {\n                    out = {}\n                    for (const attr of el.attributes) {\n                        out[attr.name] = attr.value\n                    }\n                    break\n                }\n\n                default: {\n                    out = el\n                    break\n                }\n            }\n        } catch (e) {\n            out = el\n            Ui.log(1, 'Uib:$', `Could not process output type \"${output}\" for CSS selector ${cssSelector}, returned the DOM element. ${e.message}`, e)()\n        }\n\n        return out\n    }\n\n    /** CSS query selector that returns ALL found selections. Matches the Chromium DevTools feature of the same name.\n     * NOTE that this fn returns an array showing the PROPERTIES of the elements whereas $ returns the element itself\n     * @param {string} cssSelector A CSS Selector that identifies the elements to return\n     * @param {HTMLElement} [context] Optional. The context to search within. Defaults to the document. Must be a DOM element.\n     * @returns {HTMLElement[]} Array of DOM elements/nodes. Array is empty if selector is not found.\n     */\n    $$(cssSelector, context) {\n        if (!context) context = Ui.doc\n\n        // if context is not a valid htmlelement, return null\n        if (!context || !context.nodeType) {\n            Ui.log(1, 'Uib:$$', `Invalid context element. Must be a valid HTML element.`, context)()\n            return null\n        }\n\n        return Array.from((context).querySelectorAll(cssSelector))\n    }\n\n    /** Add 1 or several class names to an element\n     * @param {string|string[]} classNames Single or array of classnames\n     * @param {HTMLElement} el HTML Element to add class(es) to\n     */\n    addClass(classNames, el) {\n        if (!Array.isArray(classNames)) classNames = [classNames]\n        if (el) el.classList.add(...classNames)\n    }\n\n    /** Apply a source template tag to a target html element\n     * NOTES:\n     * - Any attributes are only applied to the 1ST ELEMENT of the template content. Use a wrapper div if you need to apply to multiple elements.\n     * - When using 'wrap' mode, the target content is placed into the template's 1ST <slot> only (if present).\n     * - styles in ALL templates are accessible to all templates & impact the whole page.\n     * - scripts in templates are run AT TIME OF APPLICATION (so may run multiple times).\n     * - scripts in templates are applied in order of application, so variables may not yet exist if defined in subsequent templates\n     * @param {string} sourceId The HTML ID of the source element\n     * @param {string} targetId The HTML ID of the target element\n     * @param {object} config Configuration options\n     *   @param {boolean=} config.onceOnly   If true, the source will be adopted (the source is moved)\n     *   @param {object=}  config.attributes A set of key:value pairs that will be applied as attributes to the 1ST ELEMENT ONLY of the target\n     *   @param {'insert'|'replace'|'wrap'}  config.mode How to apply the template. Default is 'insert'. 'replace' will replace the targets innerHTML. 'wrap' is like 'replace' but will put any target content into the template's 1ST <slot> (if present).\n     */\n    applyTemplate(sourceId, targetId, config) {\n        if (!config) config = {}\n        if (!config.onceOnly) config.onceOnly = false\n        if (!config.mode) config.mode = 'insert'\n\n        const template = Ui.doc.getElementById(sourceId)\n        if (!template || template.tagName !== 'TEMPLATE') {\n            Ui.log('error', 'Ui:applyTemplate', `Source must be a <template>. id='${sourceId}'`)()\n            return\n        }\n\n        const target = Ui.doc.getElementById(targetId)\n        if (!target) {\n            Ui.log('error', 'Ui:applyTemplate', `Target not found: id='${targetId}'`)()\n            return\n        }\n\n        const targetContent = target.innerHTML ?? ''\n        if (targetContent && config.mode === 'replace') {\n            Ui.log('warn', 'Ui:applyTemplate', `Target element is not empty, content is replaced. id='${targetId}'`)()\n        }\n\n        let templateContent\n        if (config.onceOnly === true) templateContent = Ui.doc.adoptNode(template.content) // NB content.childElementCount = 0 after adoption\n        else templateContent = Ui.doc.importNode(template.content, true)\n\n        if (templateContent) {\n            // Apply config.attributes to the 1ST ELEMENT ONLY of the template content\n            if (config.attributes) {\n                const el = templateContent.firstElementChild\n                Object.keys(config.attributes).forEach( (attrib) => {\n                    // Apply each attribute and value\n                    el.setAttribute(attrib, config.attributes[attrib])\n                })\n            }\n\n            if (config.mode === 'insert') {\n                target.appendChild(templateContent)\n            } else if (config.mode === 'replace') {\n                target.innerHTML = ''\n                target.appendChild(templateContent)\n            } else if (config.mode === 'wrap') {\n                target.innerHTML = ''\n                target.appendChild(templateContent)\n                if (targetContent) {\n                    const slot = target.getElementsByTagName('slot')\n                    if (slot.length > 0) {\n                        slot[0].innerHTML = targetContent\n                    }\n                }\n            }\n        } else {\n            Ui.log('warn', 'Ui:applyTemplate', `No valid content found in template`)()\n        }\n    }\n\n    /** Converts markdown text input to HTML if the Markdown-IT library is loaded\n     * Otherwise simply returns the text\n     * @param {string} mdText The input markdown string\n     * @returns {string} HTML (if Markdown-IT library loaded and parse successful) or original text\n     */\n    convertMarkdown(mdText) {\n        if (!mdText) return ''\n        if (!Ui.win['markdownit']) return mdText\n        if (!Ui.md) this._markDownIt() // To handle case where the library is late loaded\n        // Convert from markdown to HTML\n        try {\n            return Ui.md.render(mdText.trim())\n        } catch (e) {\n            Ui.log(0, 'uibuilder:convertMarkdown', `Could not render Markdown. ${e.message}`, e)()\n            return '<p class=\"border error\">Could not render Markdown<p>'\n        }\n    }\n\n    /** Include HTML fragment, img, video, text, json, form data, pdf or anything else from an external file or API\n     * Wraps the included object in a div tag.\n     * PDF's, text or unknown MIME types are also wrapped in an iFrame.\n     * @param {string} url The URL of the source file to include\n     * @param {object} uiOptions Object containing properties recognised by the _uiReplace function. Must at least contain an id\n     * param {string} uiOptions.id The HTML ID given to the wrapping DIV tag\n     * param {string} uiOptions.parentSelector The CSS selector for a parent element to insert the new HTML under (defaults to 'body')\n     * @returns {Promise<any>} Status\n     */\n    async include(url, uiOptions) {\n        // TODO: src, id, parent must all be a strings\n        if (!fetch) {\n            Ui.log(0, 'Ui:include', 'Current environment does not include `fetch`, skipping.')()\n            return 'Current environment does not include `fetch`, skipping.'\n        }\n        if (!url) {\n            Ui.log(0, 'Ui:include', 'url parameter must be provided, skipping.')()\n            return 'url parameter must be provided, skipping.'\n        }\n        if (!uiOptions || !uiOptions.id) {\n            Ui.log(0, 'Ui:include', 'uiOptions parameter MUST be provided and must contain at least an `id` property, skipping.')()\n            return 'uiOptions parameter MUST be provided and must contain at least an `id` property, skipping.'\n        }\n\n        // Try to get the content via the URL\n        let response\n        try {\n            response = await fetch(url)\n        } catch (error) {\n            Ui.log(0, 'Ui:include', `Fetch of file '${url}' failed. `, error.message)()\n            return error.message\n        }\n        if (!response.ok) {\n            Ui.log(0, 'Ui:include', `Fetch of file '${url}' failed. Status='${response.statusText}'`)()\n            return response.statusText\n        }\n\n        // Work out what type of data we got\n        const contentType = await response.headers.get('content-type')\n        let type = null\n        if (contentType) {\n            if (contentType.includes('text/html')) {\n                type = 'html'\n            } else if (contentType.includes('application/json')) {\n                type = 'json'\n            } else if (contentType.includes('multipart/form-data')) {\n                type = 'form'\n            } else if (contentType.includes('image/')) {\n                type = 'image'\n            } else if (contentType.includes('video/')) {\n                type = 'video'\n            } else if (contentType.includes('application/pdf')) {\n                type = 'pdf'\n            } else if (contentType.includes('text/plain')) {\n                type = 'text'\n            } // else type = null\n        }\n\n        // Create the HTML to include on the page based on type\n        let slot = ''\n        let txtReturn = 'Include successful'\n        let data\n        switch (type) {\n            case 'html': {\n                data = await response.text()\n                slot = data\n                break\n            }\n\n            case 'json': {\n                data = await response.json()\n                slot = '<pre class=\"syntax-highlight\">'\n                slot += this.syntaxHighlight(data)\n                slot += '</pre>'\n                break\n            }\n\n            case 'form': {\n                data = await response.formData()\n                slot = '<pre class=\"syntax-highlight\">'\n                slot += this.syntaxHighlight(data)\n                slot += '</pre>'\n                break\n            }\n\n            case 'image': {\n                data = await response.blob()\n                slot = `<img src=\"${URL.createObjectURL(data)}\">`\n                if (Ui.win['DOMPurify']) {\n                    txtReturn = 'Include successful. BUT DOMPurify loaded which may block its use.'\n                    Ui.log('warn', 'Ui:include:image', txtReturn)()\n                }\n                break\n            }\n\n            case 'video': {\n                data = await response.blob()\n                slot = `<video controls autoplay><source src=\"${URL.createObjectURL(data)}\"></video>`\n                if (Ui.win['DOMPurify']) {\n                    txtReturn = 'Include successful. BUT DOMPurify loaded which may block its use.'\n                    Ui.log('warn', 'Ui:include:video', txtReturn)()\n                }\n                break\n            }\n\n            case 'pdf':\n            case 'text':\n            default: {\n                data = await response.blob()\n                slot = `<iframe style=\"resize:both;width:inherit;height:inherit;\" src=\"${URL.createObjectURL(data)}\">`\n                if (Ui.win['DOMPurify']) {\n                    txtReturn = 'Include successful. BUT DOMPurify loaded which may block its use.'\n                    Ui.log('warn', `Ui:include:${type}`, txtReturn)()\n                }\n                break\n            }\n        }\n\n        // Wrap it all in a <div id=\"...\" class=\"included\">\n        uiOptions.type = 'div'\n        uiOptions.slot = slot\n        if (!uiOptions.parent) uiOptions.parent = 'body'\n        if (!uiOptions.attributes) uiOptions.attributes = { class: 'included', }\n\n        // Use uibuilder's standard ui processing to turn the instructions into HTML\n        this._uiReplace({\n            components: [\n                uiOptions\n            ],\n        })\n\n        Ui.log('trace', `Ui:include:${type}`, txtReturn)()\n        return txtReturn\n    } // ---- End of include() ---- //\n\n    /** Attach a new remote script to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} url The url to be used in the script src attribute\n     */\n    loadScriptSrc(url) {\n        const newScript = Ui.doc.createElement('script')\n        newScript.src = url\n        newScript.async = false\n        Ui.doc.head.appendChild(newScript)\n    }\n\n    /** Attach a new text script to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} textFn The text to be loaded as a script\n     */\n    loadScriptTxt(textFn) {\n        const newScript = Ui.doc.createElement('script')\n        newScript.async = false\n        newScript.textContent = textFn\n        Ui.doc.head.appendChild(newScript)\n    }\n\n    /** Attach a new remote stylesheet link to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} url The url to be used in the style link href attribute\n     */\n    loadStyleSrc(url) {\n        const newStyle = Ui.doc.createElement('link')\n        newStyle.href = url\n        newStyle.rel = 'stylesheet'\n        newStyle.type = 'text/css'\n\n        Ui.doc.head.appendChild(newStyle)\n    }\n\n    /** Attach a new text stylesheet to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} textFn The text to be loaded as a stylesheet\n     */\n    loadStyleTxt(textFn) {\n        const newStyle = Ui.doc.createElement('style')\n        newStyle.textContent = textFn\n        Ui.doc.head.appendChild(newStyle)\n    }\n\n    /** Load a dynamic UI from a JSON web reponse\n     * @param {string} url URL that will return the ui JSON\n     */\n    loadui(url) {\n        if (!fetch) {\n            Ui.log(0, 'Ui:loadui', 'Current environment does not include `fetch`, skipping.')()\n            return\n        }\n        if (!url) {\n            Ui.log(0, 'Ui:loadui', 'url parameter must be provided, skipping.')()\n            return\n        }\n\n        fetch(url)\n            .then((response) => {\n                if (response.ok === false) {\n                    // Ui.log('warn', 'Ui:loadui:then1', `Could not load '${url}'. Status ${response.status}, Error: ${response.statusText}`)()\n                    throw new Error(`Could not load '${url}'. Status ${response.status}, Error: ${response.statusText}`)\n                }\n\n                Ui.log('trace', 'Ui:loadui:then1', `Loaded '${url}'. Status ${response.status}, ${response.statusText}`)()\n                // Did we get json?\n                const contentType = response.headers.get('content-type')\n                if (!contentType || !contentType.includes('application/json')) {\n                    throw new TypeError(`Fetch '${url}' did not return JSON, ignoring`)\n                }\n                // Returns parsed json to next .then\n                return response.json()\n            })\n            .then((data) => {\n                if (data !== undefined) {\n                    Ui.log('trace', 'Ui:loadui:then2', 'Parsed JSON successfully obtained')()\n                    // Call the _uiManager\n                    this._uiManager({ _ui: data, })\n                    return true\n                }\n                return false\n            })\n            .catch((err) => {\n                Ui.log('warn', 'Ui:loadui:catch', 'Error. ', err)()\n            })\n    } // --- end of loadui\n\n    /** ! NOT COMPLETE Move an element from one position to another\n     * @param {object} opts Options\n     * @param {string} opts.sourceSelector Required, CSS Selector that identifies the element to be moved\n     * @param {string} opts.targetSelector Required, CSS Selector that identifies the element to be moved\n     */\n    moveElement(opts) {\n        const { sourceSelector, targetSelector, moveType, position, } = opts\n        const sourceEl = document.querySelector(sourceSelector)\n        if (!sourceEl) {\n            Ui.log(0, 'Ui:moveElement', 'Source element not found')()\n            return\n        }\n        const targetEl = document.querySelector(targetSelector)\n        if (!targetEl) {\n            Ui.log(0, 'Ui:moveElement', 'Target element not found')()\n            return\n        }\n    }\n\n    /** Get standard data from a DOM node.\n     * @param {*} node DOM node to examine\n     * @param {string} cssSelector Identify the DOM element to get data from\n     * @returns {object} Standardised data object\n     */\n    nodeGet(node, cssSelector) {\n        const thisOut = {\n            id: node.id === '' ? undefined : node.id,\n            name: node.name,\n            children: node.childNodes.length,\n            type: node.nodeName,\n            attributes: undefined,\n\n            isUserInput: node.validity ? true : false,\n            userInput: !node.validity\n                ? undefined\n                : {\n                    value: node.value,\n                    validity: undefined,\n                    willValidate: node.willValidate,\n                    valueAsDate: node.valueAsDate,\n                    valueAsNumber: node.valueAsNumber,\n                    type: node.type,\n                },\n        }\n\n        if (['UL', 'OL'].includes(node.nodeName)) {\n            const listEntries = Ui.doc.querySelectorAll(`${cssSelector} li`)\n            if (listEntries) {\n                thisOut.list = {\n                    entries: listEntries.length,\n                }\n            }\n        }\n        if (node.nodeName === 'DL') {\n            const listEntries = Ui.doc.querySelectorAll(`${cssSelector} dt`)\n            if (listEntries) {\n                thisOut.list = {\n                    entries: listEntries.length,\n                }\n            }\n        }\n        if (node.nodeName === 'TABLE') {\n            const bodyEntries = Ui.doc.querySelectorAll(`${cssSelector} > tbody > tr`)\n            const headEntries = Ui.doc.querySelectorAll(`${cssSelector} > thead > tr`)\n            const cols = Ui.doc.querySelectorAll(`${cssSelector} > tbody > tr:last-child > *`) // #eltest > table > tbody > tr:nth-child(3)\n            if (bodyEntries || headEntries || cols) {\n                thisOut.table = {\n                    headRows: headEntries ? headEntries.length : 0,\n                    bodyRows: bodyEntries ? bodyEntries.length : 0,\n                    columns: cols ? cols.length : 0,\n                }\n            }\n        }\n        if (node.nodeName !== '#text' && node.attributes && node.attributes.length > 0) {\n            thisOut.attributes = {}\n            // @ts-ignore\n            for (const attrib of node.attributes) {\n                if (attrib.name !== 'id') {\n                    thisOut.attributes[attrib.name] = node.attributes[attrib.name].value\n                }\n                if (attrib.name === 'class') thisOut.classes = Array.from(node.classList)\n            }\n        }\n        if (node.nodeName === '#text') {\n            thisOut.text = node.textContent\n        }\n        if (node.validity) thisOut.userInput.validity = {}\n        for (const v in node.validity) {\n            thisOut.userInput.validity[v] = node.validity[v]\n        }\n\n        return thisOut\n    } // --- end of nodeGet --- //\n\n    /** Show a browser notification if possible. Returns a promise\n     * Config can be a simple string, a Node-RED msg (topic as title, payload as body)\n     * or a Notifications API options object + config.title string.\n     * Config ref: https://developer.mozilla.org/en-US/docs/Web/API/Notification/Notification\n     * @param {object|string} config Notification config object or simple message string\n     * @returns {Promise} Resolves on close or click event, returns the event.\n     */\n    async notification(config) {\n        if (typeof config === 'string') {\n            config = { body: config, }\n        }\n        // Are notifications available?\n        if (typeof Notification === 'undefined') return Promise.reject(new Error('Notifications not available in this browser'))\n        // Do we have permission? If not, ask for permission\n        let permit = Notification.permission\n        if (permit === 'denied') {\n            return Promise.reject(new Error('Notifications not permitted by user'))\n        } else if (permit === 'granted') {\n            return this._showNotification(config)\n        }\n        // if (permit === 'default') {\n        permit = await Notification.requestPermission()\n        if (permit === 'granted') {\n            return this._showNotification(config)\n        }\n        return Promise.reject(new Error('Notifications not permitted by user'))\n    }\n\n    /** Remove All, 1 or more class names from an element\n     * @param {undefined|null|\"\"|string|string[]} classNames Single or array of classnames. If undefined, \"\" or null, remove all classes\n     * @param {HTMLElement} el HTML Element to add class(es) to\n     */\n    removeClass(classNames, el) {\n        if (!classNames) {\n            el.removeAttribute('class')\n            return\n        }\n        if (!Array.isArray(classNames)) classNames = [classNames]\n        if (el) el.classList.remove(...classNames)\n    }\n\n    /** Replace or add an HTML element's slot from text or an HTML string\n     * WARNING: Executes <script> tags! And will process <style> tags.\n     * Will use DOMPurify if that library has been loaded to window.\n     * param {*} ui Single entry from the msg._ui property\n     * @param {Element} el Reference to the element that we want to update\n     * @param {*} slot The slot content we are trying to add/replace (defaults to empty string)\n     */\n    replaceSlot(el, slot) {\n        if (!el) return\n        if (!slot) slot = ''\n\n        // If DOMPurify is loaded, apply it now\n        slot = this.sanitiseHTML(slot)\n\n        // Override for where the el is a template, the normal handler does now work correctly\n        if (el.nodeName === 'TEMPLATE') {\n            el.innerHTML = slot\n            return\n        }\n\n        // Only use innerHTML for templates as the following does not work for them\n        // For everything else use a DocumentFragment for both security and performance.\n        //   It also preserves DOM state and does not destroy event handlers.\n\n        // Create doc frag and apply html string (msg.payload or the slot property)\n        const tempFrag = Ui.doc.createRange().createContextualFragment(slot)\n\n        // Remove content of el and replace with tempFrag\n        const elRange = Ui.doc.createRange()\n        elRange.selectNodeContents(el)\n        elRange.deleteContents()\n        el.append(tempFrag)\n    }\n\n    /** Replace or add an HTML element's slot from a Markdown string\n     * Only does something if the markdownit library has been loaded to window.\n     * Will use DOMPurify if that library has been loaded to window.\n     * @param {Element} el Reference to the element that we want to update\n     * @param {*} component The component we are trying to add/replace\n     */\n    replaceSlotMarkdown(el, component) {\n        if (!el) return\n        if (!component.slotMarkdown) return\n\n        // Convert from markdown to HTML\n        component.slotMarkdown = this.convertMarkdown(component.slotMarkdown)\n        // If DOMPurify is loaded, apply it now\n        component.slotMarkdown = this.sanitiseHTML(component.slotMarkdown)\n        // Set the component content to the the converted slotMarkdown property\n        el.innerHTML = component.slotMarkdown\n    }\n\n    /** Sanitise HTML to make it safe - if the DOMPurify library is loaded\n     * Otherwise just returns that HTML as-is.\n     * @param {string} html The input HTML string\n     * @returns {string} The sanitised HTML or the original if DOMPurify not loaded\n     */\n    sanitiseHTML(html) {\n        if (!Ui.win['DOMPurify']) return html\n        return Ui.win['DOMPurify'].sanitize(html, {\n            ADD_TAGS: this.sanitiseExtraTags,\n            ADD_ATTR: this.sanitiseExtraAttribs,\n            CUSTOM_ELEMENT_HANDLING: this.sanitiseCustomElementHandling,\n        })\n    }\n\n    // TODO - Allow notify to sit in corners rather than take over the screen\n    /** Show a pop-over \"toast\" dialog or a modal alert\n     * Refs: https://www.w3.org/WAI/ARIA/apg/example-index/dialog-modal/alertdialog.html,\n     *       https://www.w3.org/WAI/ARIA/apg/example-index/dialog-modal/dialog.html,\n     *       https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/\n     * @param {\"notify\"|\"alert\"|null} type Dialog type. If null, invalid or not provided, defaults to \"notify\".\n     * @param {object|null} ui Standardised ui data. If not provided, defaults to {noAutohide:true,modal:true,appendToast:false}\n     * @param {object} [msg] msg.payload/msg.topic - only used if payload is a string. Optional.\n     * @returns {HTMLDivElement|null} The toast element (which may disappear after a timeout) or null if no content\n     * @example\n     * Ui.showDialog('notify', { title: 'Hello', content: 'This is a notification', noAutohide: true, appendToast: true })\n     * @example\n     * Ui.showDialog('alert', null, msg)\n     */\n    showDialog(type, ui, msg) {\n        // #region -- Check properties --\n\n        if (!type || !['notify', 'alert'].includes(type)) {\n            type = 'notify' // Default to notify\n        }\n\n        if (!ui) {\n            ui = {\n                noAutohide: true,\n                modal: true,\n                appendToast: false,\n            }\n        }\n\n        let body = ''\n        // Main body content\n        if (msg.payload && typeof msg.payload === 'string') body += `<div>${msg.payload}</div>`\n        if (ui.content) body += `<div>${ui.content}</div>`\n        // Toast wont show anyway if content is empty, may as well warn user\n        if (body === '') {\n            Ui.log(1, 'Ui:showDialog', 'Toast content is blank. Not shown.')()\n            return null\n        }\n\n        // Use msg.topic as alert title if no title provided\n        let title = ''\n        if (ui.title) title = ui.title\n        else if (msg.topic) title = msg.topic\n        // if (ui.title) content = `<div class=\"toast-head\">${ui.title}</div><div class=\"toast-body\">${content}</div>`\n\n        // Allow for variants - @since v6.1 - don't bother - since this now sets CSS class, not tied to bootstrap-vue\n\n        // Toasts auto-hide by default after 10s but alerts do not auto-hide\n        if (ui.noAutohide) ui.noAutoHide = ui.noAutohide\n        if (ui.noAutoHide) ui.autohide = !ui.noAutoHide\n        // If set, number of ms until toast is auto-hidden\n        if (ui.autoHideDelay) {\n            if (!ui.autohide) ui.autohide = true\n            ui.delay = ui.autoHideDelay\n        } else ui.autoHideDelay = 10000 // default = 10s\n        if (!Object.prototype.hasOwnProperty.call(ui, 'autohide')) ui.autohide = true\n\n        let content = ''\n        let icon = ''\n        if (type === 'alert') {\n            icon = '<svg viewBox=\"0 0 192.146 192.146\"><path d=\"M108.186 144.372c0 7.054-4.729 12.32-12.037 12.32h-.254c-7.054 0-11.92-5.266-11.92-12.32 0-7.298 5.012-12.31 12.174-12.31s11.91 4.992 12.037 12.31zM88.44 125.301h15.447l2.951-61.298H85.46l2.98 61.298zm101.932 51.733c-2.237 3.664-6.214 5.921-10.493 5.921H12.282c-4.426 0-8.51-2.384-10.698-6.233a12.34 12.34 0 0 1 .147-12.349l84.111-149.22c2.208-3.722 6.204-5.96 10.522-5.96h.332c4.445.107 8.441 2.618 10.513 6.546l83.515 149.229c1.993 3.8 1.905 8.363-.352 12.066zm-10.493-6.4L96.354 21.454l-84.062 149.18h167.587z\" /></svg>'\n            ui.modal = true\n            ui.autohide = false\n        }\n        content = `<div class=\"toast-head\">${icon}${title}</div><div class=\"toast-body\">${body}</div>`\n\n        // #endregion -- -- --\n\n        const removeToaster = () => {\n            if (!toaster) return\n            Ui.doc.body.removeEventListener('keyup', toasterEventHandler)\n            toaster.removeEventListener('keyup', toasterEventHandler)\n            toaster.removeEventListener('touchend', toasterEventHandler)\n            toaster.removeEventListener('click', toasterEventHandler)\n            toaster.remove()\n        }\n\n        const removeToast = (localToast) => {\n            localToast.removeEventListener('keyup', toasterEventHandler)\n            localToast.removeEventListener('touchend', toasterEventHandler)\n            localToast.removeEventListener('click', toasterEventHandler)\n            localToast.remove()\n            // If no more toasts in the toaster, remove the toaster itself\n            if (toaster && toaster.childElementCount === 0) removeToaster()\n        }\n\n        // Prevent toaster events from affecting toast & remote itself\n        const toasterEventHandler = (evt) => {\n            evt.stopPropagation()\n            if (!toaster) return\n            console.log(\n                'toasterEventHandler',\n                evt,\n                toaster.contains(evt.target),\n                newToast.contains(evt.target),\n                newToast === evt.target\n            )\n            // removeToast(evt)\n            removeToaster()\n        }\n\n        const toastEventHandler = (evt) => {\n            evt.stopPropagation()\n\n            // Create a reference to the event target or the targets parent that has a class of 'toast'\n            let localToast\n            if (evt.target.classList.contains('toast')) {\n                localToast = evt.target\n            } else {\n                localToast = evt.target.closest('.toast')\n            }\n            if (!localToast) {\n                Ui.log(1, 'Ui:showDialog', 'Event target is not a (or in a) toast element, ignoring event')()\n                return\n            }\n\n            // Does the toast contain an input, textarea or button element?\n            const hasInteractiveElement = !!localToast.querySelector('input, textarea, button')\n\n            console.log(\n                'toastEventHandler',\n                hasInteractiveElement,\n                evt,\n                localToast.contains(evt.target),\n                localToast === evt.target\n            )\n\n            if (hasInteractiveElement) {\n                // Only respond to Escape key\n                if (evt.key !== 'Escape') return\n                // If hasInteractiveElement is true, then only close on Escape key\n                removeToast(localToast)\n            }\n\n            removeToast(localToast)\n        }\n\n        // Create a toast element (the actual dialog box). Would be nice to use <dialog> but that isn't well supported yet - come on Apple!\n        const newToast = Ui.doc.createElement('div')\n        newToast.title = 'Click or Esc to clear this notifcation'\n        newToast.setAttribute('class', `toast ${type}`)\n        newToast.setAttribute('role', type === 'alert' ? 'alertdialog' : 'dialog')\n        newToast.dataset.modal = ui.modal\n        newToast.dataset.autohide = ui.autohide\n        newToast.dataset.autoHideDelay = ui.autoHideDelay\n        // newToast.dataset.appendToast = ui.appendToast\n        newToast.innerHTML = content\n\n        // toaster.insertAdjacentElement(ui.appendToast === true ? 'beforeend' : 'afterbegin', newToast)\n        if (ui.appendToast === true) {\n            // Insert newToast after the last toast in Ui.doc.body\n            const lastToast = Array.from(Ui.doc.body.querySelectorAll('.toast')).pop()\n            if (lastToast) {\n                lastToast.insertAdjacentElement('afterend', newToast)\n            } else {\n                Ui.doc.body.insertBefore(newToast, Ui.doc.body.firstChild)\n            }\n        } else {\n            // Ui.doc.body.insertAdjacentElement('afterbegin', toaster)\n            Ui.doc.body.insertBefore(newToast, Ui.doc.body.firstChild)\n        }\n\n        // Add event handlers to each toast that still allow esc to close but only close on click if they do not contain an input, textarea or button element\n        newToast.addEventListener('keyup', toastEventHandler)\n        newToast.addEventListener('click', toastEventHandler)\n        newToast.addEventListener('touchend', toastEventHandler)\n\n        // Auto-hide each toast after a delay\n        if (ui.autohide === true) {\n            setInterval(() => {\n                // removeToaster()\n                removeToast(newToast)\n            }, ui.autoHideDelay)\n        }\n\n        // Only needed if using modal\n        let toaster\n        if (ui.modal === true) {\n            // Create a toaster container element if not already created - or get a ref to it\n            toaster = Ui.doc.getElementById('toaster')\n            if (toaster === null) {\n                toaster = Ui.doc.createElement('div')\n                toaster.id = 'toaster'\n                toaster.title = 'Click, touch, or ESC to clear notifcations'\n                toaster.setAttribute('class', 'toaster')\n                toaster.setAttribute('arial-label', 'Toast message')\n\n                toaster.addEventListener('click', toasterEventHandler)\n                toaster.addEventListener('touchend', toasterEventHandler)\n                // default active element is the body, attach the keyup event handler to the body to catch Escape key\n                Ui.doc.body.addEventListener('keyup', toasterEventHandler)\n\n                Ui.doc.body.insertAdjacentElement('afterbegin', toaster)\n            }\n        }\n\n        // Retursn a reference to the new toast element\n        return newToast\n    }\n\n    /** Creates and displays an overlay window with customizable content and behavior\n     * @param {object} options - Configuration options for the overlay\n     *   @param {string} [options.content] - Main content (text or HTML) to display\n     *   @param {string} [options.title] - Optional title above the main content\n     *   @param {string} [options.icon] - Optional icon to display left of title (HTML or text)\n     *   @param {string} [options.type] - Overlay type: 'success', 'info', 'warning', or 'error'\n     *   @param {boolean} [options.showDismiss] - Whether to show dismiss button (auto-determined if not set)\n     *   @param {number|null} [options.autoClose] - Auto-close delay in seconds (null for no auto-close)\n     *   @param {boolean} [options.time] - Show timestamp in overlay (default: true)\n     * @returns {object} Object with close() method to manually close the overlay\n     */\n    showOverlay(options) {\n        return showOverlay(options)\n    }\n\n    /** Directly manage UI via JSON\n     * @param {object} json Either an object containing {_ui: {}} or simply simple {} containing ui instructions\n     */\n    ui(json) {\n        // Simulate a msg and process\n        let msg = {}\n        if (json._ui) msg = json\n        else msg._ui = json\n\n        this._uiManager(msg)\n    }\n\n    /** Get data from the DOM. Returns selection of useful props unless a specific prop requested.\n     * @param {string} cssSelector Identify the DOM element to get data from\n     * @param {string} [propName] Optional. Specific name of property to get from the element\n     * @returns {Array<*>} Array of objects containing either specific requested property or a selection of useful properties\n     */\n    uiGet(cssSelector, propName = null) {\n        // The type cast below not really correct but it gets rid of the other typescript errors\n        const selection = /** @type {NodeListOf<HTMLInputElement>} */ (Ui.doc.querySelectorAll(cssSelector))\n\n        const out = []\n\n        selection.forEach((node) => {\n            // Specific property asked for ...\n            if (propName) {\n                if (propName === 'classes') propName = 'class'\n                // Try assuming the prop is an attribute first (will return null or \"\" if not present)\n                let prop = node.getAttribute(propName)\n                // If not an attribute, try getting as a property of the element\n                if (prop === undefined || prop === null) {\n                    try {\n                        prop = node[propName]\n                    } catch (error) {}\n                }\n                // We didn't find as either an attribute or a property\n                if (prop === undefined || prop === null) {\n                    // If 'value' was requested, return the innerText\n                    if (propName.toLowerCase() === 'value') out.push(node.innerText)\n                    else out.push(`Property '${propName}' not found`)\n                } else {\n                    const p = {}\n                    // Nightmare of different object types in a DOM Element!\n                    const cType = prop.constructor.name.toLowerCase()\n                    if (cType === 'namednodemap') {\n                        for (const key of prop) {\n                            // @ts-ignore\n                            p[key.name] = prop[key.name].value\n                        }\n                    } else if (!cType.includes('map')) { // Ordinary properties (not a mapped type)\n                        p[propName] = prop\n                    } else { // Other MAP types\n                        const p = {}\n                        // @ts-ignore\n                        for (const key in prop) {\n                            p[key] = prop[key]\n                        }\n                    }\n                    if (p.class) p.classes = Array.from(node.classList)\n                    out.push(p)\n                }\n            } else { // Otherwise, grab everything useful\n                out.push(this.nodeGet(node, cssSelector))\n            }\n        })\n\n        return out\n    }\n\n    /** External alias for _uiComposeComponent\n     * @param {*} el HTML Element to enhance\n     * @param {*} comp Individual uibuilder ui component spec\n     */\n    uiEnhanceElement(el, comp) {\n        this._uiComposeComponent(el, comp)\n    }\n\n    // #region --- table handling ---\n\n    /** Column metadata object definition\n     * @typedef columnDefinition\n     * @property {number} index The column index number\n     * @property {boolean} hasName Whether the column has a defined name or not\n     * @property {string} title The title of the column. Shown in the table header row\n     * @property {string=} name Optional. A defined column name that will be added as the `data-col-name` to all cells in the column if defined\n     * @property {string|number=} key Optional. A key value (currently unused)\n     * @property {\"string\"|\"date\"|\"number\"|\"html\"=} dataType FOR FUTURE USE. Optional. What type of data will this column contain?\n     * @property {boolean=} editable FOR FUTURE USE. Optional. Can cells in this column be edited?\n     */\n\n    /** Directly add a table to a parent element.\n     * @param {Array<object>|Array<Array>|object} data  Input data array or object. Object of objects gives named rows. Array of objects named cols. Array of arrays no naming.\n     * @param {object} [opts] Build options\n     *   @param {Array<columnDefinition>=} opts.cols Column metadata. If not provided will be derived from 1st row of data\n     *   @param {HTMLElement|string} opts.parent Default=body. The table will be added as a child. May be an actual HTML element or a CSS Selector\n     *   @param {boolean=} opts.allowHTML Optional, default=false. If true, allows HTML cell content, otherwise only allows text. Always sanitise HTML inputs\n     */\n    createTable(data = [], opts = { parent: 'body', }) {\n        if (!opts.parent) throw new Error('[ui.js:createTable] opts.parent must be provided')\n        this.buildHtmlTable(data, opts)\n    }\n\n    // TODO ...\n    /** Builds & returns an HTML table element from an array (or object) of objects\n     * 1st row is used for columns unless you pass opts.cols to describe them.\n     * If an object of objects, inner keys are used to populate th/td `data-col-name` attribs. Outer keys applied as row ID's.\n     *\n     * TODO\n     * - Allow optional caption, heading, footers, optional collapse\n     * - Multiple headings, footers\n     * - colspans, rowspans\n     * - multiple tbody\n     *\n     * @param {Array<object>|Array<Array>|object} data Input data array or object. Object of objects gives named rows. Array of objects named cols. Array of arrays no naming.\n     * @param {object} opts Table options\n     *   @param {Array<columnDefinition>=} opts.cols Column metadata. If not provided will be derived from 1st row of data\n     *   @param {HTMLElement|string=} opts.parent If provided, the table will be added as a child instead of returned. May be an actual HTML element or a CSS Selector\n     *   @param {boolean=} opts.allowHTML Optional, default=false. If true, allows HTML cell content, otherwise only allows text. Always sanitise HTML inputs\n     * @returns {HTMLTableElement|HTMLParagraphElement} Output HTML Element\n     */\n    buildHtmlTable(data, opts = {}) {\n        // If data is an object of objects, convert it to an array of objects\n        let rowKeys\n        const dataType = Object.prototype.toString.apply(data)\n        if (dataType === '[object Array]' || dataType === '[object Object]') {\n            rowKeys = Object.keys(data)\n            data = Object.values(data)\n        } else {\n            const out = Ui.doc.createElement('p')\n            out.textContent = 'Input data is not an array or an object, cannot create a table.'\n            return out\n        }\n\n        if (rowKeys.length > 1000) Ui.log(1, 'Uib:buildHtmlTable', `Warning, data is ${rowKeys.length} rows. Anything over 1,000 can get very slow to complete.`)()\n\n        const tbl = Ui.doc.createElement('table')\n\n        // Heading row\n        const thead = Ui.doc.createElement('thead')\n        const headerRow = Ui.doc.createElement('tr')\n\n        if (!opts.cols) { // Take the columns from the 1st row of provided data\n            // We have to have data\n            if (data.length < 1) throw new Error('[ui.js:buildHtmlTable] When no opts.cols is provided, data must contain at least 1 row')\n\n            const hasName = Object.prototype.toString.apply(data[0]) !== '[object Array]'\n\n            // Set this row to be the column reference (so we have a fixed ref if we allow more thead rows in the future)\n            headerRow.dataset.colReference = '' // creates attribute data-col-reference\n\n            // Create cols data: Assume 1st row of data\n            opts.cols = []\n            Object.keys(data[0]).forEach( (col, i) => {\n                opts.cols.push({\n                    index: i,\n                    hasName: hasName,\n                    name: hasName ? col : undefined,\n                    key: col ?? i,\n                    title: col,\n                })\n            })\n        }\n        // @ts-ignore Add cols metadata to table element as a custom prop\n        tbl.cols = opts.cols\n\n        // Add the table column headings\n        opts.cols.forEach((col) => {\n            const thEl = Ui.doc.createElement('th')\n            thEl.textContent = col.title\n            // @ts-ignore\n            if (col.hasName === true) thEl.dataset.colName = name\n            headerRow.appendChild(thEl)\n        })\n\n        thead.appendChild(headerRow)\n        tbl.appendChild(thead)\n\n        // body\n        const tbody = Ui.doc.createElement('tbody')\n        tbl.appendChild(tbody)\n\n        const rowOpts = {\n            allowHTML: true,\n            cols: opts.cols, // we only want to get this once\n        }\n\n        // Directly adds rows to the tbl element\n        data.forEach( (item, i) => {\n            if (isNaN(Number(rowKeys[i]))) rowOpts.rowId = rowKeys[i]\n            else rowOpts.rowId = undefined\n            this.tblAddRow(tbl, item, rowOpts)\n        })\n\n        if (opts.parent) {\n            // const parentType = Object.prototype.toString.apply(opts.parent)\n            let parentEl\n            if (typeof opts.parent === 'string') {\n                parentEl = Ui.doc.querySelector(opts.parent)\n            } else {\n                parentEl = opts.parent\n            }\n            try {\n                parentEl.appendChild(tbl)\n            } catch (e) {\n                throw new Error(`[ui.js:buildHtmlTable] Could not add table to parent. ${e.message}`)\n            }\n            return\n        }\n\n        return tbl\n    }\n\n    /** Adds (or replaces) a single row in an existing table>tbody\n     * NOTE: Row numbers use the rowIndex property of the row element.\n     * @param {string|HTMLTableElement} tbl Either a CSS Selector for the table or a reference to the HTML Table Element\n     * @param {object|Array} rowData A single row of column/cell data\n     * @param {object} [options] Additional options\n     *  @param {number=} options.body Optional, default=0. The tbody section to add the row to.\n     *  @param {boolean=} options.allowHTML Optional, default=false. If true, allows HTML cell content, otherwise only allows text. Always sanitise HTML inputs\n     *  @param {string=} options.rowId Optional. HTML element ID for the added row\n     *  @param {number=} options.afterRow Optional. If provided, the new row will be added after this row number\n     *  @param {number=} options.beforeRow Optional. If provided, the new row will be added before this row number. Ignored if afterRow is provided\n     *  @param {number=} options.replaceRow Optional. If provided, the specified row will be REPLACED instead of added. Ignored if afterRow or beforeRow is provided\n     *  @param {Array<columnDefinition>} [options.cols] Optional. Data about each column. If not provided, will be calculated from the table\n     *\n     * @returns {HTMLTableRowElement} Reference to the newly added row. Use the `rowIndex` prop for the row number\n     */\n    tblAddRow(tbl, rowData = {}, options = {}) {\n        const tblType = Object.prototype.toString.apply(tbl)\n\n        if (Object.prototype.toString.apply(options) !== '[object Object]') throw new Error(`[tblAddDataRow] options must be an object`)\n\n        // rowData must be an object or array of column cell data\n        const dataType = Object.prototype.toString.apply(rowData)\n        if (dataType !== '[object Object]' && dataType !== '[object Array]') throw new Error(`[tblAddDataRow] rowData MUST be an object or an array containing column/cell data for each column`)\n\n        /** @type {HTMLTableElement} */\n        let tblEl\n        if (tblType === '[object HTMLTableElement]') { // we were passed an actual table el\n            // @ts-ignore\n            tblEl = tbl\n        } else { // we were passed a css selector\n            // @ts-ignore\n            tblEl = Ui.doc.querySelector(tbl)\n            if (!tblEl) throw new Error(`[tblAddDataRow] Table with CSS Selector \"${tbl}\" not found`)\n        }\n\n        if (!options.body) options.body = 0\n        if (!('allowHTML' in options)) options.allowHTML = false\n\n        const tbodyEl = tblEl.getElementsByTagName('tbody')[options.body]\n        if (!tbodyEl) throw new Error(`[tblAddDataRow] Table must have a tbody tag, tbody section ${options.body} does not exist`)\n        // console.log('rows', tbody.rows.length)\n\n        // Get column meta if not provided\n        if (!options.cols) options.cols = this.tblGetColMeta(tblEl)\n        const colMeta = options.cols\n        // console.log('COL-META:', colMeta, '-- COL-META-LENGTH:', colMeta.length)\n\n        const rowEl = Ui.doc.createElement('tr')\n        if (options.rowId) rowEl.id = options.rowId\n\n        // Pre-create all the columns in an array\n        const cols = []\n        for (const col of colMeta) {\n            const cellEl = Ui.doc.createElement('td')\n            // Attach the col metadata to the col element as a custom prop\n            cellEl.colMeta = col\n            // If we have a name, add `data-col-name` attribute\n            if (col.hasName) cellEl.dataset.colName = col.name\n\n            cols.push(cellEl)\n        }\n        // console.log('COLS:', cols)\n\n        // walk through provided data\n        Object.keys(rowData).forEach( (colKey, i, row) => {\n            // console.log('++ ROW KEY. i=', i, 'rowKey=', rowKey, 'rowData[rowKey]=', rowData[rowKey])\n\n            // Match the new input to one of the columns\n            let foundEl = cols.find( col => col?.colMeta?.name === colKey )\n            let foundRowData\n            if (foundEl) { // Find by name\n                foundRowData = rowData[colKey]\n            } else { // By index\n                let numColKey = Number(colKey)\n                if (isNaN(numColKey)) numColKey = i\n                // NOTE: Ignore if the col index is larger than the number of cols\n                if (numColKey <= cols.length - 1) {\n                    foundEl = cols[numColKey]\n                    foundRowData = Object.values(rowData)[numColKey] // Gets an array even if the original is an object\n                }\n            }\n            if (foundEl) {\n                // Attach the text/html\n                if (options.allowHTML) foundEl.innerHTML = this.sanitiseHTML(foundRowData)\n                else foundEl.textContent = foundRowData\n            }\n            // Ignore not found columns\n        })\n\n        // Append all the columns to the row\n        rowEl.append(...cols)\n\n        // If afterRow is provided, insert the row after the specified row number & return reference to the new row\n        if ('afterRow' in options) {\n            const afterRow = tbodyEl.rows[options.afterRow]\n            if (afterRow) return afterRow.after(rowEl)\n        } else if ('beforeRow' in options) {\n            const beforeRow = tbodyEl.rows[options.beforeRow]\n            if (beforeRow) return beforeRow.before(rowEl)\n        } else if ('replaceRow' in options) {\n            const replaceRow = tbodyEl.rows[options.replaceRow]\n            if (replaceRow) return replaceRow.replaceWith(rowEl)\n        }\n        // Otherwise adds the row to the end of the table and returns the row reference for further processing if needed\n        return tbodyEl.appendChild(rowEl)\n    }\n\n    /** Add table event listener that returns the text or html content of either the full row or a single cell\n     * NOTE: Assumes that the table has a `tbody` element.\n     * If cells have a `data-col-name` attribute, it will be used in the output as the column name.\n     * @example tblAddListener('#eltest-tbl-table', {}, myVar)\n     * @example tblAddListener('#eltest-tbl-table', {eventScope: 'cell'}, myVar2)\n     *\n     * @param {string} tblSelector The table CSS Selector\n     * @param {object} [options] Additional options. Default={}\n     *   @param {\"row\"|\"cell\"=} options.eventScope Optional, default=row. Return data for either the whole row (as an object) or for the single cell clicked\n     *   @param {\"text\"|\"html\"=} options.returnType Optional, default=text. Return text or html data\n     *   @param {number=} options.pad Optional, default=3. Will be used to front-pad unnamed column references with zeros. e.g. 3 => \"C002\"/\"C012\"/\"C342\"\n     *   @param {boolean=} options.send Optional, default=true. If uibuilder is present, will automatically send a message back to Node-RED.\n     *   @param {string|number=} options.logLevel Optional, default=3/info. Numeric or string log level matching uibuilder's log levels.\n     *   @param {string} [options.eventType] Optional, default=click. What event to listen for.\n     * @param {object=} out A variable reference that will be updated with the output data upon a click event\n     */\n    tblAddListener(tblSelector, options = {}, out = {}) {\n        const table = Ui.doc.querySelector(tblSelector)\n        if (!table) throw new Error(`Table with CSS Selector \"${tblSelector}\" not found`)\n        if (typeof out !== 'object') throw new Error('The \"out\" argument MUST be an object')\n\n        if (!options.eventScope) options.eventScope = 'row'\n        if (!options.returnType) options.returnType = 'text'\n        if (!options.eventType) options.eventType = 'click'\n        if (!options.pad) options.pad = 3\n        if (!options.logLevel) options.logLevel = 2 // info\n        if (!('send' in options)) options.send = true\n\n        // Add event listener to the table's <tbody> to capture clicks on any <tr> within it\n        table.querySelector('tbody').addEventListener(options.eventType, (event) => {\n            Object.keys(out).forEach(key => delete out[key]) // empty the out object\n\n            const clickedRow = event.target.closest('tr')\n            const clickedCell = event.target.closest('td')\n            // console.log('element clicked: ', clickedEl)\n\n            if (clickedRow) {\n                out.clickType = options.eventScope\n                out.eventType = options.eventType\n\n                const rowIndex = out.rowIndex = clickedRow.rowIndex\n                const cellIndex = out.cellIndex = clickedCell.cellIndex + 1 // Madness! rowindex starts from 1 but cell index from 0!\n\n                if (clickedRow.id) out.rowId = clickedRow.id\n\n                if (options.eventScope === 'row') {\n                    // Loop through each <td> in the clicked row\n                    clickedRow.querySelectorAll('td').forEach((cell) => {\n                        const colName = this.tblGetCellName(cell, options.pad)\n                        out[colName] = options.returnType === 'text' ? cell.textContent.trim() : cell.innerHTML\n                    })\n                } else {\n                    const colName = this.tblGetCellName(clickedCell, options.pad)\n                    out[colName] = options.returnType === 'text' ? clickedCell.textContent.trim() : clickedCell.innerHTML\n                }\n\n                Ui.log(options.logLevel, 'Ui:tblAddClickListener', `${options.eventScope} ${options.eventType} on row=${rowIndex}, col=${cellIndex}, data: `, out)()\n\n                // If UIBUILDER for Node-RED client library, send a message back to Node-RED\n                if (options.send === true && Ui.win['uibuilder']) Ui.win['uibuilder'].send({\n                    topic: `${tblSelector} ${options.eventScope} ${options.eventType}`,\n                    payload: out,\n                })\n            }\n        })\n    }\n\n    /** Find the column definition for a single column\n     * @param {string|number} rowKey Key or index to use for column search\n     * @param {Array<columnDefinition>=} colMeta Array of column definitions. If not provided, will need the HTML table element.\n     * @param {HTMLTableElement=} tblEl If the colMeta table not provided, provide the HTML table element to do the lookup\n     * @returns {columnDefinition} Column metadata object\n     */\n    tblFindColMeta(rowKey, colMeta, tblEl) {\n        if (!colMeta && !tblEl) throw new Error('[tblFindColMeta] Either the column metadata array or the HTML table element must be provided')\n        if (!colMeta && tblEl) colMeta = this.tblGetColMeta(tblEl)\n\n        let colDef\n        if (colMeta[rowKey]) colDef = colMeta[rowKey]\n        else {\n            const find = colMeta.find( c => c.name === rowKey || c.index === Number(rowKey) )\n            // console.log('FIND:', find)\n            if (find) colDef = find\n        }\n        // console.log('== COL DEF', colDef)\n        return colDef\n    }\n\n    /** Return a standardised table cell name. Either from a `data-col-name` attribute or a numeric reference like `C003`\n     * @param {HTMLTableCellElement} cellEl The cell element to process\n     * @param {number=} pad Optional, default=3. Will be used to front-pad unnamed column references with zeros. e.g. 3 => \"C002\"/\"C012\"/\"C342\"\n     * @returns {string} A cell name\n     */\n    tblGetCellName(cellEl, pad = 3) {\n        return cellEl.getAttribute('data-col-name') ?? `C${String(cellEl.cellIndex + 1).padStart(pad, '0')}`\n    }\n\n    /** Returns either the existing or calculated column metadata given any table\n     * First checks if the data is on the `cols` custom property of the table\n     * If not, then looks 1st for a row with a `data-col-reference` attribute. Then for the first TR of the thead. Then for the first TR of the table.\n     * @param {HTMLTableElement} tblEl DOM table element\n     * @param {object} [options] Additional options. Default={}\n     *   @param {number=} options.pad Optional, default=3. Will be used to front-pad unnamed column references with zeros. e.g. 3 => \"C002\"/\"C012\"/\"C342\"\n     * @returns {Array<columnDefinition>} Column metadata = array of column definitions\n     */\n    tblGetColMeta(tblEl, options = {}) {\n        if (!options.pad) options.pad = 3\n\n        // @ts-ignore If the table already has the cols custom prop, simply return it\n        if (tblEl.cols) return tblEl.cols\n\n        let cols = tblEl.querySelector('tr[data-col-reference]')?.children\n        if (!cols) cols = tblEl.querySelector('thead>tr:first-of-type')?.children\n        if (!cols) cols = tblEl.querySelector('tr:first-of-type')?.children\n\n        if (!cols) {\n            Ui.log(1, 'Ui:tblGetColMeta', 'No columns found in table')()\n            return []\n        }\n\n        const colData = []\n\n        /** @type {HTMLTableCellElement} */ let cellEl\n        for (cellEl of cols) {\n            const hasName = !!cellEl.dataset.colName\n            const colName = cellEl.dataset.colName\n            const colIndex = cellEl.cellIndex + 1\n            const colKey = hasName ? colName : `C${String(cellEl.cellIndex + 1).padStart(options.pad, '0')}`\n\n            colData.push({\n                index: colIndex,\n                hasName: hasName,\n                name: colName,\n                key: colKey,\n                title: cellEl.textContent,\n            })\n        }\n\n        // @ts-ignore Add the custom prop to the table element\n        tblEl.cols = colData\n\n        return colData\n    }\n\n    /** Remove a row from an existing table\n     * @param {string|HTMLTableElement} tbl Either a CSS Selector for the table or a reference to the HTML Table Element\n     * @param {number} rowIndex The row number to remove (1st row is 0, last row is -1)\n     * @param {object} [options] Additional options\n     *  @param {number=} options.body Optional, default=0. The tbody section to add the row to.\n     */\n    tblRemoveRow(tbl, rowIndex, options = {}) {\n        const tblType = Object.prototype.toString.apply(tbl)\n\n        if (Object.prototype.toString.apply(options) !== '[object Object]') throw new Error(`[tblRemoveRow] options must be an object`)\n\n        /** @type {HTMLTableElement} */\n        let tblEl\n        if (tblType === '[object HTMLTableElement]') { // we were passed an actual table el\n            // @ts-ignore\n            tblEl = tbl\n        } else { // we were passed a css selector\n            // @ts-ignore\n            tblEl = Ui.doc.querySelector(tbl)\n            if (!tblEl) throw new Error(`[tblRemoveRow] Table with CSS Selector \"${tbl}\" not found`)\n        }\n\n        if (!options.body) options.body = 0\n\n        const tbodyEl = tblEl.getElementsByTagName('tbody')[options.body]\n        if (!tbodyEl) throw new Error(`[tblAddDataRow] Table must have a tbody tag, tbody section ${options.body} does not exist`)\n\n        tbodyEl.deleteRow(rowIndex)\n    }\n\n    // #endregion --- table handling ---\n}\n\nexport default Ui\n\n// if (window) window['$ui'] = new Ui(window)\n\n// export Ui\n", "const PACKET_TYPES = Object.create(null); // no Map = no polyfill\nPACKET_TYPES[\"open\"] = \"0\";\nPACKET_TYPES[\"close\"] = \"1\";\nPACKET_TYPES[\"ping\"] = \"2\";\nPACKET_TYPES[\"pong\"] = \"3\";\nPACKET_TYPES[\"message\"] = \"4\";\nPACKET_TYPES[\"upgrade\"] = \"5\";\nPACKET_TYPES[\"noop\"] = \"6\";\nconst PACKET_TYPES_REVERSE = Object.create(null);\nObject.keys(PACKET_TYPES).forEach((key) => {\n    PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key;\n});\nconst ERROR_PACKET = { type: \"error\", data: \"parser error\" };\nexport { PACKET_TYPES, PACKET_TYPES_REVERSE, ERROR_PACKET };\n", "import { PACKET_TYPES } from \"./commons.js\";\nconst withNativeBlob = typeof Blob === \"function\" ||\n    (typeof Blob !== \"undefined\" &&\n        Object.prototype.toString.call(Blob) === \"[object BlobConstructor]\");\nconst withNativeArrayBuffer = typeof ArrayBuffer === \"function\";\n// ArrayBuffer.isView method is not defined in IE10\nconst isView = (obj) => {\n    return typeof ArrayBuffer.isView === \"function\"\n        ? ArrayBuffer.isView(obj)\n        : obj && obj.buffer instanceof ArrayBuffer;\n};\nconst encodePacket = ({ type, data }, supportsBinary, callback) => {\n    if (withNativeBlob && data instanceof Blob) {\n        if (supportsBinary) {\n            return callback(data);\n        }\n        else {\n            return encodeBlobAsBase64(data, callback);\n        }\n    }\n    else if (withNativeArrayBuffer &&\n        (data instanceof ArrayBuffer || isView(data))) {\n        if (supportsBinary) {\n            return callback(data);\n        }\n        else {\n            return encodeBlobAsBase64(new Blob([data]), callback);\n        }\n    }\n    // plain string\n    return callback(PACKET_TYPES[type] + (data || \"\"));\n};\nconst encodeBlobAsBase64 = (data, callback) => {\n    const fileReader = new FileReader();\n    fileReader.onload = function () {\n        const content = fileReader.result.split(\",\")[1];\n        callback(\"b\" + (content || \"\"));\n    };\n    return fileReader.readAsDataURL(data);\n};\nfunction toArray(data) {\n    if (data instanceof Uint8Array) {\n        return data;\n    }\n    else if (data instanceof ArrayBuffer) {\n        return new Uint8Array(data);\n    }\n    else {\n        return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);\n    }\n}\nlet TEXT_ENCODER;\nexport function encodePacketToBinary(packet, callback) {\n    if (withNativeBlob && packet.data instanceof Blob) {\n        return packet.data.arrayBuffer().then(toArray).then(callback);\n    }\n    else if (withNativeArrayBuffer &&\n        (packet.data instanceof ArrayBuffer || isView(packet.data))) {\n        return callback(toArray(packet.data));\n    }\n    encodePacket(packet, false, (encoded) => {\n        if (!TEXT_ENCODER) {\n            TEXT_ENCODER = new TextEncoder();\n        }\n        callback(TEXT_ENCODER.encode(encoded));\n    });\n}\nexport { encodePacket };\n", "// imported from https://github.com/socketio/base64-arraybuffer\nconst chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n// Use a lookup table to find the index.\nconst lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);\nfor (let i = 0; i < chars.length; i++) {\n    lookup[chars.charCodeAt(i)] = i;\n}\nexport const encode = (arraybuffer) => {\n    let bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = '';\n    for (i = 0; i < len; i += 3) {\n        base64 += chars[bytes[i] >> 2];\n        base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];\n        base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];\n        base64 += chars[bytes[i + 2] & 63];\n    }\n    if (len % 3 === 2) {\n        base64 = base64.substring(0, base64.length - 1) + '=';\n    }\n    else if (len % 3 === 1) {\n        base64 = base64.substring(0, base64.length - 2) + '==';\n    }\n    return base64;\n};\nexport const decode = (base64) => {\n    let bufferLength = base64.length * 0.75, len = base64.length, i, p = 0, encoded1, encoded2, encoded3, encoded4;\n    if (base64[base64.length - 1] === '=') {\n        bufferLength--;\n        if (base64[base64.length - 2] === '=') {\n            bufferLength--;\n        }\n    }\n    const arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer);\n    for (i = 0; i < len; i += 4) {\n        encoded1 = lookup[base64.charCodeAt(i)];\n        encoded2 = lookup[base64.charCodeAt(i + 1)];\n        encoded3 = lookup[base64.charCodeAt(i + 2)];\n        encoded4 = lookup[base64.charCodeAt(i + 3)];\n        bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);\n        bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);\n        bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);\n    }\n    return arraybuffer;\n};\n", "import { ERROR_PACKET, PACKET_TYPES_REVERSE, } from \"./commons.js\";\nimport { decode } from \"./contrib/base64-arraybuffer.js\";\nconst withNativeArrayBuffer = typeof ArrayBuffer === \"function\";\nexport const decodePacket = (encodedPacket, binaryType) => {\n    if (typeof encodedPacket !== \"string\") {\n        return {\n            type: \"message\",\n            data: mapBinary(encodedPacket, binaryType),\n        };\n    }\n    const type = encodedPacket.charAt(0);\n    if (type === \"b\") {\n        return {\n            type: \"message\",\n            data: decodeBase64Packet(encodedPacket.substring(1), binaryType),\n        };\n    }\n    const packetType = PACKET_TYPES_REVERSE[type];\n    if (!packetType) {\n        return ERROR_PACKET;\n    }\n    return encodedPacket.length > 1\n        ? {\n            type: PACKET_TYPES_REVERSE[type],\n            data: encodedPacket.substring(1),\n        }\n        : {\n            type: PACKET_TYPES_REVERSE[type],\n        };\n};\nconst decodeBase64Packet = (data, binaryType) => {\n    if (withNativeArrayBuffer) {\n        const decoded = decode(data);\n        return mapBinary(decoded, binaryType);\n    }\n    else {\n        return { base64: true, data }; // fallback for old browsers\n    }\n};\nconst mapBinary = (data, binaryType) => {\n    switch (binaryType) {\n        case \"blob\":\n            if (data instanceof Blob) {\n                // from WebSocket + binaryType \"blob\"\n                return data;\n            }\n            else {\n                // from HTTP long-polling or WebTransport\n                return new Blob([data]);\n            }\n        case \"arraybuffer\":\n        default:\n            if (data instanceof ArrayBuffer) {\n                // from HTTP long-polling (base64) or WebSocket + binaryType \"arraybuffer\"\n                return data;\n            }\n            else {\n                // from WebTransport (Uint8Array)\n                return data.buffer;\n            }\n    }\n};\n", "import { encodePacket, encodePacketToBinary } from \"./encodePacket.js\";\nimport { decodePacket } from \"./decodePacket.js\";\nimport { ERROR_PACKET, } from \"./commons.js\";\nconst SEPARATOR = String.fromCharCode(30); // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text\nconst encodePayload = (packets, callback) => {\n    // some packets may be added to the array while encoding, so the initial length must be saved\n    const length = packets.length;\n    const encodedPackets = new Array(length);\n    let count = 0;\n    packets.forEach((packet, i) => {\n        // force base64 encoding for binary packets\n        encodePacket(packet, false, (encodedPacket) => {\n            encodedPackets[i] = encodedPacket;\n            if (++count === length) {\n                callback(encodedPackets.join(SEPARATOR));\n            }\n        });\n    });\n};\nconst decodePayload = (encodedPayload, binaryType) => {\n    const encodedPackets = encodedPayload.split(SEPARATOR);\n    const packets = [];\n    for (let i = 0; i < encodedPackets.length; i++) {\n        const decodedPacket = decodePacket(encodedPackets[i], binaryType);\n        packets.push(decodedPacket);\n        if (decodedPacket.type === \"error\") {\n            break;\n        }\n    }\n    return packets;\n};\nexport function createPacketEncoderStream() {\n    return new TransformStream({\n        transform(packet, controller) {\n            encodePacketToBinary(packet, (encodedPacket) => {\n                const payloadLength = encodedPacket.length;\n                let header;\n                // inspired by the WebSocket format: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#decoding_payload_length\n                if (payloadLength < 126) {\n                    header = new Uint8Array(1);\n                    new DataView(header.buffer).setUint8(0, payloadLength);\n                }\n                else if (payloadLength < 65536) {\n                    header = new Uint8Array(3);\n                    const view = new DataView(header.buffer);\n                    view.setUint8(0, 126);\n                    view.setUint16(1, payloadLength);\n                }\n                else {\n                    header = new Uint8Array(9);\n                    const view = new DataView(header.buffer);\n                    view.setUint8(0, 127);\n                    view.setBigUint64(1, BigInt(payloadLength));\n                }\n                // first bit indicates whether the payload is plain text (0) or binary (1)\n                if (packet.data && typeof packet.data !== \"string\") {\n                    header[0] |= 0x80;\n                }\n                controller.enqueue(header);\n                controller.enqueue(encodedPacket);\n            });\n        },\n    });\n}\nlet TEXT_DECODER;\nfunction totalLength(chunks) {\n    return chunks.reduce((acc, chunk) => acc + chunk.length, 0);\n}\nfunction concatChunks(chunks, size) {\n    if (chunks[0].length === size) {\n        return chunks.shift();\n    }\n    const buffer = new Uint8Array(size);\n    let j = 0;\n    for (let i = 0; i < size; i++) {\n        buffer[i] = chunks[0][j++];\n        if (j === chunks[0].length) {\n            chunks.shift();\n            j = 0;\n        }\n    }\n    if (chunks.length && j < chunks[0].length) {\n        chunks[0] = chunks[0].slice(j);\n    }\n    return buffer;\n}\nexport function createPacketDecoderStream(maxPayload, binaryType) {\n    if (!TEXT_DECODER) {\n        TEXT_DECODER = new TextDecoder();\n    }\n    const chunks = [];\n    let state = 0 /* State.READ_HEADER */;\n    let expectedLength = -1;\n    let isBinary = false;\n    return new TransformStream({\n        transform(chunk, controller) {\n            chunks.push(chunk);\n            while (true) {\n                if (state === 0 /* State.READ_HEADER */) {\n                    if (totalLength(chunks) < 1) {\n                        break;\n                    }\n                    const header = concatChunks(chunks, 1);\n                    isBinary = (header[0] & 0x80) === 0x80;\n                    expectedLength = header[0] & 0x7f;\n                    if (expectedLength < 126) {\n                        state = 3 /* State.READ_PAYLOAD */;\n                    }\n                    else if (expectedLength === 126) {\n                        state = 1 /* State.READ_EXTENDED_LENGTH_16 */;\n                    }\n                    else {\n                        state = 2 /* State.READ_EXTENDED_LENGTH_64 */;\n                    }\n                }\n                else if (state === 1 /* State.READ_EXTENDED_LENGTH_16 */) {\n                    if (totalLength(chunks) < 2) {\n                        break;\n                    }\n                    const headerArray = concatChunks(chunks, 2);\n                    expectedLength = new DataView(headerArray.buffer, headerArray.byteOffset, headerArray.length).getUint16(0);\n                    state = 3 /* State.READ_PAYLOAD */;\n                }\n                else if (state === 2 /* State.READ_EXTENDED_LENGTH_64 */) {\n                    if (totalLength(chunks) < 8) {\n                        break;\n                    }\n                    const headerArray = concatChunks(chunks, 8);\n                    const view = new DataView(headerArray.buffer, headerArray.byteOffset, headerArray.length);\n                    const n = view.getUint32(0);\n                    if (n > Math.pow(2, 53 - 32) - 1) {\n                        // the maximum safe integer in JavaScript is 2^53 - 1\n                        controller.enqueue(ERROR_PACKET);\n                        break;\n                    }\n                    expectedLength = n * Math.pow(2, 32) + view.getUint32(4);\n                    state = 3 /* State.READ_PAYLOAD */;\n                }\n                else {\n                    if (totalLength(chunks) < expectedLength) {\n                        break;\n                    }\n                    const data = concatChunks(chunks, expectedLength);\n                    controller.enqueue(decodePacket(isBinary ? data : TEXT_DECODER.decode(data), binaryType));\n                    state = 0 /* State.READ_HEADER */;\n                }\n                if (expectedLength === 0 || expectedLength > maxPayload) {\n                    controller.enqueue(ERROR_PACKET);\n                    break;\n                }\n            }\n        },\n    });\n}\nexport const protocol = 4;\nexport { encodePacket, encodePayload, decodePacket, decodePayload, };\n", "/**\n * Initialize a new `Emitter`.\n *\n * @api public\n */\n\nexport function Emitter(obj) {\n  if (obj) return mixin(obj);\n}\n\n/**\n * Mixin the emitter properties.\n *\n * @param {Object} obj\n * @return {Object}\n * @api private\n */\n\nfunction mixin(obj) {\n  for (var key in Emitter.prototype) {\n    obj[key] = Emitter.prototype[key];\n  }\n  return obj;\n}\n\n/**\n * Listen on the given `event` with `fn`.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.on =\nEmitter.prototype.addEventListener = function(event, fn){\n  this._callbacks = this._callbacks || {};\n  (this._callbacks['$' + event] = this._callbacks['$' + event] || [])\n    .push(fn);\n  return this;\n};\n\n/**\n * Adds an `event` listener that will be invoked a single\n * time then automatically removed.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.once = function(event, fn){\n  function on() {\n    this.off(event, on);\n    fn.apply(this, arguments);\n  }\n\n  on.fn = fn;\n  this.on(event, on);\n  return this;\n};\n\n/**\n * Remove the given callback for `event` or all\n * registered callbacks.\n *\n * @param {String} event\n * @param {Function} fn\n * @return {Emitter}\n * @api public\n */\n\nEmitter.prototype.off =\nEmitter.prototype.removeListener =\nEmitter.prototype.removeAllListeners =\nEmitter.prototype.removeEventListener = function(event, fn){\n  this._callbacks = this._callbacks || {};\n\n  // all\n  if (0 == arguments.length) {\n    this._callbacks = {};\n    return this;\n  }\n\n  // specific event\n  var callbacks = this._callbacks['$' + event];\n  if (!callbacks) return this;\n\n  // remove all handlers\n  if (1 == arguments.length) {\n    delete this._callbacks['$' + event];\n    return this;\n  }\n\n  // remove specific handler\n  var cb;\n  for (var i = 0; i < callbacks.length; i++) {\n    cb = callbacks[i];\n    if (cb === fn || cb.fn === fn) {\n      callbacks.splice(i, 1);\n      break;\n    }\n  }\n\n  // Remove event specific arrays for event types that no\n  // one is subscribed for to avoid memory leak.\n  if (callbacks.length === 0) {\n    delete this._callbacks['$' + event];\n  }\n\n  return this;\n};\n\n/**\n * Emit `event` with the given args.\n *\n * @param {String} event\n * @param {Mixed} ...\n * @return {Emitter}\n */\n\nEmitter.prototype.emit = function(event){\n  this._callbacks = this._callbacks || {};\n\n  var args = new Array(arguments.length - 1)\n    , callbacks = this._callbacks['$' + event];\n\n  for (var i = 1; i < arguments.length; i++) {\n    args[i - 1] = arguments[i];\n  }\n\n  if (callbacks) {\n    callbacks = callbacks.slice(0);\n    for (var i = 0, len = callbacks.length; i < len; ++i) {\n      callbacks[i].apply(this, args);\n    }\n  }\n\n  return this;\n};\n\n// alias used for reserved events (protected method)\nEmitter.prototype.emitReserved = Emitter.prototype.emit;\n\n/**\n * Return array of callbacks for `event`.\n *\n * @param {String} event\n * @return {Array}\n * @api public\n */\n\nEmitter.prototype.listeners = function(event){\n  this._callbacks = this._callbacks || {};\n  return this._callbacks['$' + event] || [];\n};\n\n/**\n * Check if this emitter has `event` handlers.\n *\n * @param {String} event\n * @return {Boolean}\n * @api public\n */\n\nEmitter.prototype.hasListeners = function(event){\n  return !! this.listeners(event).length;\n};\n", "export const nextTick = (() => {\n    const isPromiseAvailable = typeof Promise === \"function\" && typeof Promise.resolve === \"function\";\n    if (isPromiseAvailable) {\n        return (cb) => Promise.resolve().then(cb);\n    }\n    else {\n        return (cb, setTimeoutFn) => setTimeoutFn(cb, 0);\n    }\n})();\nexport const globalThisShim = (() => {\n    if (typeof self !== \"undefined\") {\n        return self;\n    }\n    else if (typeof window !== \"undefined\") {\n        return window;\n    }\n    else {\n        return Function(\"return this\")();\n    }\n})();\nexport const defaultBinaryType = \"arraybuffer\";\nexport function createCookieJar() { }\n", "import { globalThisShim as globalThis } from \"./globals.node.js\";\nexport function pick(obj, ...attr) {\n    return attr.reduce((acc, k) => {\n        if (obj.hasOwnProperty(k)) {\n            acc[k] = obj[k];\n        }\n        return acc;\n    }, {});\n}\n// Keep a reference to the real timeout functions so they can be used when overridden\nconst NATIVE_SET_TIMEOUT = globalThis.setTimeout;\nconst NATIVE_CLEAR_TIMEOUT = globalThis.clearTimeout;\nexport function installTimerFunctions(obj, opts) {\n    if (opts.useNativeTimers) {\n        obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThis);\n        obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThis);\n    }\n    else {\n        obj.setTimeoutFn = globalThis.setTimeout.bind(globalThis);\n        obj.clearTimeoutFn = globalThis.clearTimeout.bind(globalThis);\n    }\n}\n// base64 encoded buffers are about 33% bigger (https://en.wikipedia.org/wiki/Base64)\nconst BASE64_OVERHEAD = 1.33;\n// we could also have used `new Blob([obj]).size`, but it isn't supported in IE9\nexport function byteLength(obj) {\n    if (typeof obj === \"string\") {\n        return utf8Length(obj);\n    }\n    // arraybuffer or blob\n    return Math.ceil((obj.byteLength || obj.size) * BASE64_OVERHEAD);\n}\nfunction utf8Length(str) {\n    let c = 0, length = 0;\n    for (let i = 0, l = str.length; i < l; i++) {\n        c = str.charCodeAt(i);\n        if (c < 0x80) {\n            length += 1;\n        }\n        else if (c < 0x800) {\n            length += 2;\n        }\n        else if (c < 0xd800 || c >= 0xe000) {\n            length += 3;\n        }\n        else {\n            i++;\n            length += 4;\n        }\n    }\n    return length;\n}\n/**\n * Generates a random 8-characters string.\n */\nexport function randomString() {\n    return (Date.now().toString(36).substring(3) +\n        Math.random().toString(36).substring(2, 5));\n}\n", "// imported from https://github.com/galkn/querystring\n/**\n * Compiles a querystring\n * Returns string representation of the object\n *\n * @param {Object}\n * @api private\n */\nexport function encode(obj) {\n    let str = '';\n    for (let i in obj) {\n        if (obj.hasOwnProperty(i)) {\n            if (str.length)\n                str += '&';\n            str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);\n        }\n    }\n    return str;\n}\n/**\n * Parses a simple querystring into an object\n *\n * @param {String} qs\n * @api private\n */\nexport function decode(qs) {\n    let qry = {};\n    let pairs = qs.split('&');\n    for (let i = 0, l = pairs.length; i < l; i++) {\n        let pair = pairs[i].split('=');\n        qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);\n    }\n    return qry;\n}\n", "import { decodePacket } from \"engine.io-parser\";\nimport { Emitter } from \"@socket.io/component-emitter\";\nimport { installTimerFunctions } from \"./util.js\";\nimport { encode } from \"./contrib/parseqs.js\";\nexport class TransportError extends Error {\n    constructor(reason, description, context) {\n        super(reason);\n        this.description = description;\n        this.context = context;\n        this.type = \"TransportError\";\n    }\n}\nexport class Transport extends Emitter {\n    /**\n     * Transport abstract constructor.\n     *\n     * @param {Object} opts - options\n     * @protected\n     */\n    constructor(opts) {\n        super();\n        this.writable = false;\n        installTimerFunctions(this, opts);\n        this.opts = opts;\n        this.query = opts.query;\n        this.socket = opts.socket;\n        this.supportsBinary = !opts.forceBase64;\n    }\n    /**\n     * Emits an error.\n     *\n     * @param {String} reason\n     * @param description\n     * @param context - the error context\n     * @return {Transport} for chaining\n     * @protected\n     */\n    onError(reason, description, context) {\n        super.emitReserved(\"error\", new TransportError(reason, description, context));\n        return this;\n    }\n    /**\n     * Opens the transport.\n     */\n    open() {\n        this.readyState = \"opening\";\n        this.doOpen();\n        return this;\n    }\n    /**\n     * Closes the transport.\n     */\n    close() {\n        if (this.readyState === \"opening\" || this.readyState === \"open\") {\n            this.doClose();\n            this.onClose();\n        }\n        return this;\n    }\n    /**\n     * Sends multiple packets.\n     *\n     * @param {Array} packets\n     */\n    send(packets) {\n        if (this.readyState === \"open\") {\n            this.write(packets);\n        }\n        else {\n            // this might happen if the transport was silently closed in the beforeunload event handler\n        }\n    }\n    /**\n     * Called upon open\n     *\n     * @protected\n     */\n    onOpen() {\n        this.readyState = \"open\";\n        this.writable = true;\n        super.emitReserved(\"open\");\n    }\n    /**\n     * Called with data.\n     *\n     * @param {String} data\n     * @protected\n     */\n    onData(data) {\n        const packet = decodePacket(data, this.socket.binaryType);\n        this.onPacket(packet);\n    }\n    /**\n     * Called with a decoded packet.\n     *\n     * @protected\n     */\n    onPacket(packet) {\n        super.emitReserved(\"packet\", packet);\n    }\n    /**\n     * Called upon close.\n     *\n     * @protected\n     */\n    onClose(details) {\n        this.readyState = \"closed\";\n        super.emitReserved(\"close\", details);\n    }\n    /**\n     * Pauses the transport, in order not to lose packets during an upgrade.\n     *\n     * @param onPause\n     */\n    pause(onPause) { }\n    createUri(schema, query = {}) {\n        return (schema +\n            \"://\" +\n            this._hostname() +\n            this._port() +\n            this.opts.path +\n            this._query(query));\n    }\n    _hostname() {\n        const hostname = this.opts.hostname;\n        return hostname.indexOf(\":\") === -1 ? hostname : \"[\" + hostname + \"]\";\n    }\n    _port() {\n        if (this.opts.port &&\n            ((this.opts.secure && Number(this.opts.port) !== 443) ||\n                (!this.opts.secure && Number(this.opts.port) !== 80))) {\n            return \":\" + this.opts.port;\n        }\n        else {\n            return \"\";\n        }\n    }\n    _query(query) {\n        const encodedQuery = encode(query);\n        return encodedQuery.length ? \"?\" + encodedQuery : \"\";\n    }\n}\n", "import { Transport } from \"../transport.js\";\nimport { randomString } from \"../util.js\";\nimport { encodePayload, decodePayload } from \"engine.io-parser\";\nexport class Polling extends Transport {\n    constructor() {\n        super(...arguments);\n        this._polling = false;\n    }\n    get name() {\n        return \"polling\";\n    }\n    /**\n     * Opens the socket (triggers polling). We write a PING message to determine\n     * when the transport is open.\n     *\n     * @protected\n     */\n    doOpen() {\n        this._poll();\n    }\n    /**\n     * Pauses polling.\n     *\n     * @param {Function} onPause - callback upon buffers are flushed and transport is paused\n     * @package\n     */\n    pause(onPause) {\n        this.readyState = \"pausing\";\n        const pause = () => {\n            this.readyState = \"paused\";\n            onPause();\n        };\n        if (this._polling || !this.writable) {\n            let total = 0;\n            if (this._polling) {\n                total++;\n                this.once(\"pollComplete\", function () {\n                    --total || pause();\n                });\n            }\n            if (!this.writable) {\n                total++;\n                this.once(\"drain\", function () {\n                    --total || pause();\n                });\n            }\n        }\n        else {\n            pause();\n        }\n    }\n    /**\n     * Starts polling cycle.\n     *\n     * @private\n     */\n    _poll() {\n        this._polling = true;\n        this.doPoll();\n        this.emitReserved(\"poll\");\n    }\n    /**\n     * Overloads onData to detect payloads.\n     *\n     * @protected\n     */\n    onData(data) {\n        const callback = (packet) => {\n            // if its the first message we consider the transport open\n            if (\"opening\" === this.readyState && packet.type === \"open\") {\n                this.onOpen();\n            }\n            // if its a close packet, we close the ongoing requests\n            if (\"close\" === packet.type) {\n                this.onClose({ description: \"transport closed by the server\" });\n                return false;\n            }\n            // otherwise bypass onData and handle the message\n            this.onPacket(packet);\n        };\n        // decode payload\n        decodePayload(data, this.socket.binaryType).forEach(callback);\n        // if an event did not trigger closing\n        if (\"closed\" !== this.readyState) {\n            // if we got data we're not polling\n            this._polling = false;\n            this.emitReserved(\"pollComplete\");\n            if (\"open\" === this.readyState) {\n                this._poll();\n            }\n            else {\n            }\n        }\n    }\n    /**\n     * For polling, send a close packet.\n     *\n     * @protected\n     */\n    doClose() {\n        const close = () => {\n            this.write([{ type: \"close\" }]);\n        };\n        if (\"open\" === this.readyState) {\n            close();\n        }\n        else {\n            // in case we're trying to close while\n            // handshaking is in progress (GH-164)\n            this.once(\"open\", close);\n        }\n    }\n    /**\n     * Writes a packets payload.\n     *\n     * @param {Array} packets - data packets\n     * @protected\n     */\n    write(packets) {\n        this.writable = false;\n        encodePayload(packets, (data) => {\n            this.doWrite(data, () => {\n                this.writable = true;\n                this.emitReserved(\"drain\");\n            });\n        });\n    }\n    /**\n     * Generates uri for connection.\n     *\n     * @private\n     */\n    uri() {\n        const schema = this.opts.secure ? \"https\" : \"http\";\n        const query = this.query || {};\n        // cache busting is forced\n        if (false !== this.opts.timestampRequests) {\n            query[this.opts.timestampParam] = randomString();\n        }\n        if (!this.supportsBinary && !query.sid) {\n            query.b64 = 1;\n        }\n        return this.createUri(schema, query);\n    }\n}\n", "// imported from https://github.com/component/has-cors\nlet value = false;\ntry {\n    value = typeof XMLHttpRequest !== 'undefined' &&\n        'withCredentials' in new XMLHttpRequest();\n}\ncatch (err) {\n    // if XMLHttp support is disabled in IE then it will throw\n    // when trying to create\n}\nexport const hasCORS = value;\n", "import { Polling } from \"./polling.js\";\nimport { Emitter } from \"@socket.io/component-emitter\";\nimport { installTimerFunctions, pick } from \"../util.js\";\nimport { globalThisShim as globalThis } from \"../globals.node.js\";\nimport { hasCORS } from \"../contrib/has-cors.js\";\nfunction empty() { }\nexport class BaseXHR extends Polling {\n    /**\n     * XHR Polling constructor.\n     *\n     * @param {Object} opts\n     * @package\n     */\n    constructor(opts) {\n        super(opts);\n        if (typeof location !== \"undefined\") {\n            const isSSL = \"https:\" === location.protocol;\n            let port = location.port;\n            // some user agents have empty `location.port`\n            if (!port) {\n                port = isSSL ? \"443\" : \"80\";\n            }\n            this.xd =\n                (typeof location !== \"undefined\" &&\n                    opts.hostname !== location.hostname) ||\n                    port !== opts.port;\n        }\n    }\n    /**\n     * Sends data.\n     *\n     * @param {String} data - data to send.\n     * @param {Function} fn - called upon flush.\n     * @private\n     */\n    doWrite(data, fn) {\n        const req = this.request({\n            method: \"POST\",\n            data: data,\n        });\n        req.on(\"success\", fn);\n        req.on(\"error\", (xhrStatus, context) => {\n            this.onError(\"xhr post error\", xhrStatus, context);\n        });\n    }\n    /**\n     * Starts a poll cycle.\n     *\n     * @private\n     */\n    doPoll() {\n        const req = this.request();\n        req.on(\"data\", this.onData.bind(this));\n        req.on(\"error\", (xhrStatus, context) => {\n            this.onError(\"xhr poll error\", xhrStatus, context);\n        });\n        this.pollXhr = req;\n    }\n}\nexport class Request extends Emitter {\n    /**\n     * Request constructor\n     *\n     * @param {Object} options\n     * @package\n     */\n    constructor(createRequest, uri, opts) {\n        super();\n        this.createRequest = createRequest;\n        installTimerFunctions(this, opts);\n        this._opts = opts;\n        this._method = opts.method || \"GET\";\n        this._uri = uri;\n        this._data = undefined !== opts.data ? opts.data : null;\n        this._create();\n    }\n    /**\n     * Creates the XHR object and sends the request.\n     *\n     * @private\n     */\n    _create() {\n        var _a;\n        const opts = pick(this._opts, \"agent\", \"pfx\", \"key\", \"passphrase\", \"cert\", \"ca\", \"ciphers\", \"rejectUnauthorized\", \"autoUnref\");\n        opts.xdomain = !!this._opts.xd;\n        const xhr = (this._xhr = this.createRequest(opts));\n        try {\n            xhr.open(this._method, this._uri, true);\n            try {\n                if (this._opts.extraHeaders) {\n                    // @ts-ignore\n                    xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);\n                    for (let i in this._opts.extraHeaders) {\n                        if (this._opts.extraHeaders.hasOwnProperty(i)) {\n                            xhr.setRequestHeader(i, this._opts.extraHeaders[i]);\n                        }\n                    }\n                }\n            }\n            catch (e) { }\n            if (\"POST\" === this._method) {\n                try {\n                    xhr.setRequestHeader(\"Content-type\", \"text/plain;charset=UTF-8\");\n                }\n                catch (e) { }\n            }\n            try {\n                xhr.setRequestHeader(\"Accept\", \"*/*\");\n            }\n            catch (e) { }\n            (_a = this._opts.cookieJar) === null || _a === void 0 ? void 0 : _a.addCookies(xhr);\n            // ie6 check\n            if (\"withCredentials\" in xhr) {\n                xhr.withCredentials = this._opts.withCredentials;\n            }\n            if (this._opts.requestTimeout) {\n                xhr.timeout = this._opts.requestTimeout;\n            }\n            xhr.onreadystatechange = () => {\n                var _a;\n                if (xhr.readyState === 3) {\n                    (_a = this._opts.cookieJar) === null || _a === void 0 ? void 0 : _a.parseCookies(\n                    // @ts-ignore\n                    xhr.getResponseHeader(\"set-cookie\"));\n                }\n                if (4 !== xhr.readyState)\n                    return;\n                if (200 === xhr.status || 1223 === xhr.status) {\n                    this._onLoad();\n                }\n                else {\n                    // make sure the `error` event handler that's user-set\n                    // does not throw in the same tick and gets caught here\n                    this.setTimeoutFn(() => {\n                        this._onError(typeof xhr.status === \"number\" ? xhr.status : 0);\n                    }, 0);\n                }\n            };\n            xhr.send(this._data);\n        }\n        catch (e) {\n            // Need to defer since .create() is called directly from the constructor\n            // and thus the 'error' event can only be only bound *after* this exception\n            // occurs.  Therefore, also, we cannot throw here at all.\n            this.setTimeoutFn(() => {\n                this._onError(e);\n            }, 0);\n            return;\n        }\n        if (typeof document !== \"undefined\") {\n            this._index = Request.requestsCount++;\n            Request.requests[this._index] = this;\n        }\n    }\n    /**\n     * Called upon error.\n     *\n     * @private\n     */\n    _onError(err) {\n        this.emitReserved(\"error\", err, this._xhr);\n        this._cleanup(true);\n    }\n    /**\n     * Cleans up house.\n     *\n     * @private\n     */\n    _cleanup(fromError) {\n        if (\"undefined\" === typeof this._xhr || null === this._xhr) {\n            return;\n        }\n        this._xhr.onreadystatechange = empty;\n        if (fromError) {\n            try {\n                this._xhr.abort();\n            }\n            catch (e) { }\n        }\n        if (typeof document !== \"undefined\") {\n            delete Request.requests[this._index];\n        }\n        this._xhr = null;\n    }\n    /**\n     * Called upon load.\n     *\n     * @private\n     */\n    _onLoad() {\n        const data = this._xhr.responseText;\n        if (data !== null) {\n            this.emitReserved(\"data\", data);\n            this.emitReserved(\"success\");\n            this._cleanup();\n        }\n    }\n    /**\n     * Aborts the request.\n     *\n     * @package\n     */\n    abort() {\n        this._cleanup();\n    }\n}\nRequest.requestsCount = 0;\nRequest.requests = {};\n/**\n * Aborts pending requests when unloading the window. This is needed to prevent\n * memory leaks (e.g. when using IE) and to ensure that no spurious error is\n * emitted.\n */\nif (typeof document !== \"undefined\") {\n    // @ts-ignore\n    if (typeof attachEvent === \"function\") {\n        // @ts-ignore\n        attachEvent(\"onunload\", unloadHandler);\n    }\n    else if (typeof addEventListener === \"function\") {\n        const terminationEvent = \"onpagehide\" in globalThis ? \"pagehide\" : \"unload\";\n        addEventListener(terminationEvent, unloadHandler, false);\n    }\n}\nfunction unloadHandler() {\n    for (let i in Request.requests) {\n        if (Request.requests.hasOwnProperty(i)) {\n            Request.requests[i].abort();\n        }\n    }\n}\nconst hasXHR2 = (function () {\n    const xhr = newRequest({\n        xdomain: false,\n    });\n    return xhr && xhr.responseType !== null;\n})();\n/**\n * HTTP long-polling based on the built-in `XMLHttpRequest` object.\n *\n * Usage: browser\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest\n */\nexport class XHR extends BaseXHR {\n    constructor(opts) {\n        super(opts);\n        const forceBase64 = opts && opts.forceBase64;\n        this.supportsBinary = hasXHR2 && !forceBase64;\n    }\n    request(opts = {}) {\n        Object.assign(opts, { xd: this.xd }, this.opts);\n        return new Request(newRequest, this.uri(), opts);\n    }\n}\nfunction newRequest(opts) {\n    const xdomain = opts.xdomain;\n    // XMLHttpRequest can be disabled on IE\n    try {\n        if (\"undefined\" !== typeof XMLHttpRequest && (!xdomain || hasCORS)) {\n            return new XMLHttpRequest();\n        }\n    }\n    catch (e) { }\n    if (!xdomain) {\n        try {\n            return new globalThis[[\"Active\"].concat(\"Object\").join(\"X\")](\"Microsoft.XMLHTTP\");\n        }\n        catch (e) { }\n    }\n}\n", "import { Transport } from \"../transport.js\";\nimport { pick, randomString } from \"../util.js\";\nimport { encodePacket } from \"engine.io-parser\";\nimport { globalThisShim as globalThis, nextTick } from \"../globals.node.js\";\n// detect ReactNative environment\nconst isReactNative = typeof navigator !== \"undefined\" &&\n    typeof navigator.product === \"string\" &&\n    navigator.product.toLowerCase() === \"reactnative\";\nexport class BaseWS extends Transport {\n    get name() {\n        return \"websocket\";\n    }\n    doOpen() {\n        const uri = this.uri();\n        const protocols = this.opts.protocols;\n        // React Native only supports the 'headers' option, and will print a warning if anything else is passed\n        const opts = isReactNative\n            ? {}\n            : pick(this.opts, \"agent\", \"perMessageDeflate\", \"pfx\", \"key\", \"passphrase\", \"cert\", \"ca\", \"ciphers\", \"rejectUnauthorized\", \"localAddress\", \"protocolVersion\", \"origin\", \"maxPayload\", \"family\", \"checkServerIdentity\");\n        if (this.opts.extraHeaders) {\n            opts.headers = this.opts.extraHeaders;\n        }\n        try {\n            this.ws = this.createSocket(uri, protocols, opts);\n        }\n        catch (err) {\n            return this.emitReserved(\"error\", err);\n        }\n        this.ws.binaryType = this.socket.binaryType;\n        this.addEventListeners();\n    }\n    /**\n     * Adds event listeners to the socket\n     *\n     * @private\n     */\n    addEventListeners() {\n        this.ws.onopen = () => {\n            if (this.opts.autoUnref) {\n                this.ws._socket.unref();\n            }\n            this.onOpen();\n        };\n        this.ws.onclose = (closeEvent) => this.onClose({\n            description: \"websocket connection closed\",\n            context: closeEvent,\n        });\n        this.ws.onmessage = (ev) => this.onData(ev.data);\n        this.ws.onerror = (e) => this.onError(\"websocket error\", e);\n    }\n    write(packets) {\n        this.writable = false;\n        // encodePacket efficient as it uses WS framing\n        // no need for encodePayload\n        for (let i = 0; i < packets.length; i++) {\n            const packet = packets[i];\n            const lastPacket = i === packets.length - 1;\n            encodePacket(packet, this.supportsBinary, (data) => {\n                // Sometimes the websocket has already been closed but the browser didn't\n                // have a chance of informing us about it yet, in that case send will\n                // throw an error\n                try {\n                    this.doWrite(packet, data);\n                }\n                catch (e) {\n                }\n                if (lastPacket) {\n                    // fake drain\n                    // defer to next tick to allow Socket to clear writeBuffer\n                    nextTick(() => {\n                        this.writable = true;\n                        this.emitReserved(\"drain\");\n                    }, this.setTimeoutFn);\n                }\n            });\n        }\n    }\n    doClose() {\n        if (typeof this.ws !== \"undefined\") {\n            this.ws.onerror = () => { };\n            this.ws.close();\n            this.ws = null;\n        }\n    }\n    /**\n     * Generates uri for connection.\n     *\n     * @private\n     */\n    uri() {\n        const schema = this.opts.secure ? \"wss\" : \"ws\";\n        const query = this.query || {};\n        // append timestamp to URI\n        if (this.opts.timestampRequests) {\n            query[this.opts.timestampParam] = randomString();\n        }\n        // communicate binary support capabilities\n        if (!this.supportsBinary) {\n            query.b64 = 1;\n        }\n        return this.createUri(schema, query);\n    }\n}\nconst WebSocketCtor = globalThis.WebSocket || globalThis.MozWebSocket;\n/**\n * WebSocket transport based on the built-in `WebSocket` object.\n *\n * Usage: browser, Node.js (since v21), Deno, Bun\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket\n * @see https://caniuse.com/mdn-api_websocket\n * @see https://nodejs.org/api/globals.html#websocket\n */\nexport class WS extends BaseWS {\n    createSocket(uri, protocols, opts) {\n        return !isReactNative\n            ? protocols\n                ? new WebSocketCtor(uri, protocols)\n                : new WebSocketCtor(uri)\n            : new WebSocketCtor(uri, protocols, opts);\n    }\n    doWrite(_packet, data) {\n        this.ws.send(data);\n    }\n}\n", "import { Transport } from \"../transport.js\";\nimport { nextTick } from \"../globals.node.js\";\nimport { createPacketDecoderStream, createPacketEncoderStream, } from \"engine.io-parser\";\n/**\n * WebTransport transport based on the built-in `WebTransport` object.\n *\n * Usage: browser, Node.js (with the `@fails-components/webtransport` package)\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/WebTransport\n * @see https://caniuse.com/webtransport\n */\nexport class WT extends Transport {\n    get name() {\n        return \"webtransport\";\n    }\n    doOpen() {\n        try {\n            // @ts-ignore\n            this._transport = new WebTransport(this.createUri(\"https\"), this.opts.transportOptions[this.name]);\n        }\n        catch (err) {\n            return this.emitReserved(\"error\", err);\n        }\n        this._transport.closed\n            .then(() => {\n            this.onClose();\n        })\n            .catch((err) => {\n            this.onError(\"webtransport error\", err);\n        });\n        // note: we could have used async/await, but that would require some additional polyfills\n        this._transport.ready.then(() => {\n            this._transport.createBidirectionalStream().then((stream) => {\n                const decoderStream = createPacketDecoderStream(Number.MAX_SAFE_INTEGER, this.socket.binaryType);\n                const reader = stream.readable.pipeThrough(decoderStream).getReader();\n                const encoderStream = createPacketEncoderStream();\n                encoderStream.readable.pipeTo(stream.writable);\n                this._writer = encoderStream.writable.getWriter();\n                const read = () => {\n                    reader\n                        .read()\n                        .then(({ done, value }) => {\n                        if (done) {\n                            return;\n                        }\n                        this.onPacket(value);\n                        read();\n                    })\n                        .catch((err) => {\n                    });\n                };\n                read();\n                const packet = { type: \"open\" };\n                if (this.query.sid) {\n                    packet.data = `{\"sid\":\"${this.query.sid}\"}`;\n                }\n                this._writer.write(packet).then(() => this.onOpen());\n            });\n        });\n    }\n    write(packets) {\n        this.writable = false;\n        for (let i = 0; i < packets.length; i++) {\n            const packet = packets[i];\n            const lastPacket = i === packets.length - 1;\n            this._writer.write(packet).then(() => {\n                if (lastPacket) {\n                    nextTick(() => {\n                        this.writable = true;\n                        this.emitReserved(\"drain\");\n                    }, this.setTimeoutFn);\n                }\n            });\n        }\n    }\n    doClose() {\n        var _a;\n        (_a = this._transport) === null || _a === void 0 ? void 0 : _a.close();\n    }\n}\n", "import { XHR } from \"./polling-xhr.node.js\";\nimport { WS } from \"./websocket.node.js\";\nimport { WT } from \"./webtransport.js\";\nexport const transports = {\n    websocket: WS,\n    webtransport: WT,\n    polling: XHR,\n};\n", "// imported from https://github.com/galkn/parseuri\n/**\n * Parses a URI\n *\n * Note: we could also have used the built-in URL object, but it isn't supported on all platforms.\n *\n * See:\n * - https://developer.mozilla.org/en-US/docs/Web/API/URL\n * - https://caniuse.com/url\n * - https://www.rfc-editor.org/rfc/rfc3986#appendix-B\n *\n * History of the parse() method:\n * - first commit: https://github.com/socketio/socket.io-client/commit/4ee1d5d94b3906a9c052b459f1a818b15f38f91c\n * - export into its own module: https://github.com/socketio/engine.io-client/commit/de2c561e4564efeb78f1bdb1ba39ef81b2822cb3\n * - reimport: https://github.com/socketio/engine.io-client/commit/df32277c3f6d622eec5ed09f493cae3f3391d242\n *\n * @author Steven Levithan <stevenlevithan.com> (MIT license)\n * @api private\n */\nconst re = /^(?:(?![^:@\\/?#]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@\\/?#]*)(?::([^:@\\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;\nconst parts = [\n    'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'\n];\nexport function parse(str) {\n    if (str.length > 8000) {\n        throw \"URI too long\";\n    }\n    const src = str, b = str.indexOf('['), e = str.indexOf(']');\n    if (b != -1 && e != -1) {\n        str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);\n    }\n    let m = re.exec(str || ''), uri = {}, i = 14;\n    while (i--) {\n        uri[parts[i]] = m[i] || '';\n    }\n    if (b != -1 && e != -1) {\n        uri.source = src;\n        uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');\n        uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');\n        uri.ipv6uri = true;\n    }\n    uri.pathNames = pathNames(uri, uri['path']);\n    uri.queryKey = queryKey(uri, uri['query']);\n    return uri;\n}\nfunction pathNames(obj, path) {\n    const regx = /\\/{2,9}/g, names = path.replace(regx, \"/\").split(\"/\");\n    if (path.slice(0, 1) == '/' || path.length === 0) {\n        names.splice(0, 1);\n    }\n    if (path.slice(-1) == '/') {\n        names.splice(names.length - 1, 1);\n    }\n    return names;\n}\nfunction queryKey(uri, query) {\n    const data = {};\n    query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function ($0, $1, $2) {\n        if ($1) {\n            data[$1] = $2;\n        }\n    });\n    return data;\n}\n", "import { transports as DEFAULT_TRANSPORTS } from \"./transports/index.js\";\nimport { installTimerFunctions, byteLength } from \"./util.js\";\nimport { decode } from \"./contrib/parseqs.js\";\nimport { parse } from \"./contrib/parseuri.js\";\nimport { Emitter } from \"@socket.io/component-emitter\";\nimport { protocol } from \"engine.io-parser\";\nimport { createCookieJar, defaultBinaryType, nextTick, } from \"./globals.node.js\";\nconst withEventListeners = typeof addEventListener === \"function\" &&\n    typeof removeEventListener === \"function\";\nconst OFFLINE_EVENT_LISTENERS = [];\nif (withEventListeners) {\n    // within a ServiceWorker, any event handler for the 'offline' event must be added on the initial evaluation of the\n    // script, so we create one single event listener here which will forward the event to the socket instances\n    addEventListener(\"offline\", () => {\n        OFFLINE_EVENT_LISTENERS.forEach((listener) => listener());\n    }, false);\n}\n/**\n * This class provides a WebSocket-like interface to connect to an Engine.IO server. The connection will be established\n * with one of the available low-level transports, like HTTP long-polling, WebSocket or WebTransport.\n *\n * This class comes without upgrade mechanism, which means that it will keep the first low-level transport that\n * successfully establishes the connection.\n *\n * In order to allow tree-shaking, there are no transports included, that's why the `transports` option is mandatory.\n *\n * @example\n * import { SocketWithoutUpgrade, WebSocket } from \"engine.io-client\";\n *\n * const socket = new SocketWithoutUpgrade({\n *   transports: [WebSocket]\n * });\n *\n * socket.on(\"open\", () => {\n *   socket.send(\"hello\");\n * });\n *\n * @see SocketWithUpgrade\n * @see Socket\n */\nexport class SocketWithoutUpgrade extends Emitter {\n    /**\n     * Socket constructor.\n     *\n     * @param {String|Object} uri - uri or options\n     * @param {Object} opts - options\n     */\n    constructor(uri, opts) {\n        super();\n        this.binaryType = defaultBinaryType;\n        this.writeBuffer = [];\n        this._prevBufferLen = 0;\n        this._pingInterval = -1;\n        this._pingTimeout = -1;\n        this._maxPayload = -1;\n        /**\n         * The expiration timestamp of the {@link _pingTimeoutTimer} object is tracked, in case the timer is throttled and the\n         * callback is not fired on time. This can happen for example when a laptop is suspended or when a phone is locked.\n         */\n        this._pingTimeoutTime = Infinity;\n        if (uri && \"object\" === typeof uri) {\n            opts = uri;\n            uri = null;\n        }\n        if (uri) {\n            const parsedUri = parse(uri);\n            opts.hostname = parsedUri.host;\n            opts.secure =\n                parsedUri.protocol === \"https\" || parsedUri.protocol === \"wss\";\n            opts.port = parsedUri.port;\n            if (parsedUri.query)\n                opts.query = parsedUri.query;\n        }\n        else if (opts.host) {\n            opts.hostname = parse(opts.host).host;\n        }\n        installTimerFunctions(this, opts);\n        this.secure =\n            null != opts.secure\n                ? opts.secure\n                : typeof location !== \"undefined\" && \"https:\" === location.protocol;\n        if (opts.hostname && !opts.port) {\n            // if no port is specified manually, use the protocol default\n            opts.port = this.secure ? \"443\" : \"80\";\n        }\n        this.hostname =\n            opts.hostname ||\n                (typeof location !== \"undefined\" ? location.hostname : \"localhost\");\n        this.port =\n            opts.port ||\n                (typeof location !== \"undefined\" && location.port\n                    ? location.port\n                    : this.secure\n                        ? \"443\"\n                        : \"80\");\n        this.transports = [];\n        this._transportsByName = {};\n        opts.transports.forEach((t) => {\n            const transportName = t.prototype.name;\n            this.transports.push(transportName);\n            this._transportsByName[transportName] = t;\n        });\n        this.opts = Object.assign({\n            path: \"/engine.io\",\n            agent: false,\n            withCredentials: false,\n            upgrade: true,\n            timestampParam: \"t\",\n            rememberUpgrade: false,\n            addTrailingSlash: true,\n            rejectUnauthorized: true,\n            perMessageDeflate: {\n                threshold: 1024,\n            },\n            transportOptions: {},\n            closeOnBeforeunload: false,\n        }, opts);\n        this.opts.path =\n            this.opts.path.replace(/\\/$/, \"\") +\n                (this.opts.addTrailingSlash ? \"/\" : \"\");\n        if (typeof this.opts.query === \"string\") {\n            this.opts.query = decode(this.opts.query);\n        }\n        if (withEventListeners) {\n            if (this.opts.closeOnBeforeunload) {\n                // Firefox closes the connection when the \"beforeunload\" event is emitted but not Chrome. This event listener\n                // ensures every browser behaves the same (no \"disconnect\" event at the Socket.IO level when the page is\n                // closed/reloaded)\n                this._beforeunloadEventListener = () => {\n                    if (this.transport) {\n                        // silently close the transport\n                        this.transport.removeAllListeners();\n                        this.transport.close();\n                    }\n                };\n                addEventListener(\"beforeunload\", this._beforeunloadEventListener, false);\n            }\n            if (this.hostname !== \"localhost\") {\n                this._offlineEventListener = () => {\n                    this._onClose(\"transport close\", {\n                        description: \"network connection lost\",\n                    });\n                };\n                OFFLINE_EVENT_LISTENERS.push(this._offlineEventListener);\n            }\n        }\n        if (this.opts.withCredentials) {\n            this._cookieJar = createCookieJar();\n        }\n        this._open();\n    }\n    /**\n     * Creates transport of the given type.\n     *\n     * @param {String} name - transport name\n     * @return {Transport}\n     * @private\n     */\n    createTransport(name) {\n        const query = Object.assign({}, this.opts.query);\n        // append engine.io protocol identifier\n        query.EIO = protocol;\n        // transport name\n        query.transport = name;\n        // session id if we already have one\n        if (this.id)\n            query.sid = this.id;\n        const opts = Object.assign({}, this.opts, {\n            query,\n            socket: this,\n            hostname: this.hostname,\n            secure: this.secure,\n            port: this.port,\n        }, this.opts.transportOptions[name]);\n        return new this._transportsByName[name](opts);\n    }\n    /**\n     * Initializes transport to use and starts probe.\n     *\n     * @private\n     */\n    _open() {\n        if (this.transports.length === 0) {\n            // Emit error on next tick so it can be listened to\n            this.setTimeoutFn(() => {\n                this.emitReserved(\"error\", \"No transports available\");\n            }, 0);\n            return;\n        }\n        const transportName = this.opts.rememberUpgrade &&\n            SocketWithoutUpgrade.priorWebsocketSuccess &&\n            this.transports.indexOf(\"websocket\") !== -1\n            ? \"websocket\"\n            : this.transports[0];\n        this.readyState = \"opening\";\n        const transport = this.createTransport(transportName);\n        transport.open();\n        this.setTransport(transport);\n    }\n    /**\n     * Sets the current transport. Disables the existing one (if any).\n     *\n     * @private\n     */\n    setTransport(transport) {\n        if (this.transport) {\n            this.transport.removeAllListeners();\n        }\n        // set up transport\n        this.transport = transport;\n        // set up transport listeners\n        transport\n            .on(\"drain\", this._onDrain.bind(this))\n            .on(\"packet\", this._onPacket.bind(this))\n            .on(\"error\", this._onError.bind(this))\n            .on(\"close\", (reason) => this._onClose(\"transport close\", reason));\n    }\n    /**\n     * Called when connection is deemed open.\n     *\n     * @private\n     */\n    onOpen() {\n        this.readyState = \"open\";\n        SocketWithoutUpgrade.priorWebsocketSuccess =\n            \"websocket\" === this.transport.name;\n        this.emitReserved(\"open\");\n        this.flush();\n    }\n    /**\n     * Handles a packet.\n     *\n     * @private\n     */\n    _onPacket(packet) {\n        if (\"opening\" === this.readyState ||\n            \"open\" === this.readyState ||\n            \"closing\" === this.readyState) {\n            this.emitReserved(\"packet\", packet);\n            // Socket is live - any packet counts\n            this.emitReserved(\"heartbeat\");\n            switch (packet.type) {\n                case \"open\":\n                    this.onHandshake(JSON.parse(packet.data));\n                    break;\n                case \"ping\":\n                    this._sendPacket(\"pong\");\n                    this.emitReserved(\"ping\");\n                    this.emitReserved(\"pong\");\n                    this._resetPingTimeout();\n                    break;\n                case \"error\":\n                    const err = new Error(\"server error\");\n                    // @ts-ignore\n                    err.code = packet.data;\n                    this._onError(err);\n                    break;\n                case \"message\":\n                    this.emitReserved(\"data\", packet.data);\n                    this.emitReserved(\"message\", packet.data);\n                    break;\n            }\n        }\n        else {\n        }\n    }\n    /**\n     * Called upon handshake completion.\n     *\n     * @param {Object} data - handshake obj\n     * @private\n     */\n    onHandshake(data) {\n        this.emitReserved(\"handshake\", data);\n        this.id = data.sid;\n        this.transport.query.sid = data.sid;\n        this._pingInterval = data.pingInterval;\n        this._pingTimeout = data.pingTimeout;\n        this._maxPayload = data.maxPayload;\n        this.onOpen();\n        // In case open handler closes socket\n        if (\"closed\" === this.readyState)\n            return;\n        this._resetPingTimeout();\n    }\n    /**\n     * Sets and resets ping timeout timer based on server pings.\n     *\n     * @private\n     */\n    _resetPingTimeout() {\n        this.clearTimeoutFn(this._pingTimeoutTimer);\n        const delay = this._pingInterval + this._pingTimeout;\n        this._pingTimeoutTime = Date.now() + delay;\n        this._pingTimeoutTimer = this.setTimeoutFn(() => {\n            this._onClose(\"ping timeout\");\n        }, delay);\n        if (this.opts.autoUnref) {\n            this._pingTimeoutTimer.unref();\n        }\n    }\n    /**\n     * Called on `drain` event\n     *\n     * @private\n     */\n    _onDrain() {\n        this.writeBuffer.splice(0, this._prevBufferLen);\n        // setting prevBufferLen = 0 is very important\n        // for example, when upgrading, upgrade packet is sent over,\n        // and a nonzero prevBufferLen could cause problems on `drain`\n        this._prevBufferLen = 0;\n        if (0 === this.writeBuffer.length) {\n            this.emitReserved(\"drain\");\n        }\n        else {\n            this.flush();\n        }\n    }\n    /**\n     * Flush write buffers.\n     *\n     * @private\n     */\n    flush() {\n        if (\"closed\" !== this.readyState &&\n            this.transport.writable &&\n            !this.upgrading &&\n            this.writeBuffer.length) {\n            const packets = this._getWritablePackets();\n            this.transport.send(packets);\n            // keep track of current length of writeBuffer\n            // splice writeBuffer and callbackBuffer on `drain`\n            this._prevBufferLen = packets.length;\n            this.emitReserved(\"flush\");\n        }\n    }\n    /**\n     * Ensure the encoded size of the writeBuffer is below the maxPayload value sent by the server (only for HTTP\n     * long-polling)\n     *\n     * @private\n     */\n    _getWritablePackets() {\n        const shouldCheckPayloadSize = this._maxPayload &&\n            this.transport.name === \"polling\" &&\n            this.writeBuffer.length > 1;\n        if (!shouldCheckPayloadSize) {\n            return this.writeBuffer;\n        }\n        let payloadSize = 1; // first packet type\n        for (let i = 0; i < this.writeBuffer.length; i++) {\n            const data = this.writeBuffer[i].data;\n            if (data) {\n                payloadSize += byteLength(data);\n            }\n            if (i > 0 && payloadSize > this._maxPayload) {\n                return this.writeBuffer.slice(0, i);\n            }\n            payloadSize += 2; // separator + packet type\n        }\n        return this.writeBuffer;\n    }\n    /**\n     * Checks whether the heartbeat timer has expired but the socket has not yet been notified.\n     *\n     * Note: this method is private for now because it does not really fit the WebSocket API, but if we put it in the\n     * `write()` method then the message would not be buffered by the Socket.IO client.\n     *\n     * @return {boolean}\n     * @private\n     */\n    /* private */ _hasPingExpired() {\n        if (!this._pingTimeoutTime)\n            return true;\n        const hasExpired = Date.now() > this._pingTimeoutTime;\n        if (hasExpired) {\n            this._pingTimeoutTime = 0;\n            nextTick(() => {\n                this._onClose(\"ping timeout\");\n            }, this.setTimeoutFn);\n        }\n        return hasExpired;\n    }\n    /**\n     * Sends a message.\n     *\n     * @param {String} msg - message.\n     * @param {Object} options.\n     * @param {Function} fn - callback function.\n     * @return {Socket} for chaining.\n     */\n    write(msg, options, fn) {\n        this._sendPacket(\"message\", msg, options, fn);\n        return this;\n    }\n    /**\n     * Sends a message. Alias of {@link Socket#write}.\n     *\n     * @param {String} msg - message.\n     * @param {Object} options.\n     * @param {Function} fn - callback function.\n     * @return {Socket} for chaining.\n     */\n    send(msg, options, fn) {\n        this._sendPacket(\"message\", msg, options, fn);\n        return this;\n    }\n    /**\n     * Sends a packet.\n     *\n     * @param {String} type - packet type.\n     * @param {String} data.\n     * @param {Object} options.\n     * @param {Function} fn - callback function.\n     * @private\n     */\n    _sendPacket(type, data, options, fn) {\n        if (\"function\" === typeof data) {\n            fn = data;\n            data = undefined;\n        }\n        if (\"function\" === typeof options) {\n            fn = options;\n            options = null;\n        }\n        if (\"closing\" === this.readyState || \"closed\" === this.readyState) {\n            return;\n        }\n        options = options || {};\n        options.compress = false !== options.compress;\n        const packet = {\n            type: type,\n            data: data,\n            options: options,\n        };\n        this.emitReserved(\"packetCreate\", packet);\n        this.writeBuffer.push(packet);\n        if (fn)\n            this.once(\"flush\", fn);\n        this.flush();\n    }\n    /**\n     * Closes the connection.\n     */\n    close() {\n        const close = () => {\n            this._onClose(\"forced close\");\n            this.transport.close();\n        };\n        const cleanupAndClose = () => {\n            this.off(\"upgrade\", cleanupAndClose);\n            this.off(\"upgradeError\", cleanupAndClose);\n            close();\n        };\n        const waitForUpgrade = () => {\n            // wait for upgrade to finish since we can't send packets while pausing a transport\n            this.once(\"upgrade\", cleanupAndClose);\n            this.once(\"upgradeError\", cleanupAndClose);\n        };\n        if (\"opening\" === this.readyState || \"open\" === this.readyState) {\n            this.readyState = \"closing\";\n            if (this.writeBuffer.length) {\n                this.once(\"drain\", () => {\n                    if (this.upgrading) {\n                        waitForUpgrade();\n                    }\n                    else {\n                        close();\n                    }\n                });\n            }\n            else if (this.upgrading) {\n                waitForUpgrade();\n            }\n            else {\n                close();\n            }\n        }\n        return this;\n    }\n    /**\n     * Called upon transport error\n     *\n     * @private\n     */\n    _onError(err) {\n        SocketWithoutUpgrade.priorWebsocketSuccess = false;\n        if (this.opts.tryAllTransports &&\n            this.transports.length > 1 &&\n            this.readyState === \"opening\") {\n            this.transports.shift();\n            return this._open();\n        }\n        this.emitReserved(\"error\", err);\n        this._onClose(\"transport error\", err);\n    }\n    /**\n     * Called upon transport close.\n     *\n     * @private\n     */\n    _onClose(reason, description) {\n        if (\"opening\" === this.readyState ||\n            \"open\" === this.readyState ||\n            \"closing\" === this.readyState) {\n            // clear timers\n            this.clearTimeoutFn(this._pingTimeoutTimer);\n            // stop event from firing again for transport\n            this.transport.removeAllListeners(\"close\");\n            // ensure transport won't stay open\n            this.transport.close();\n            // ignore further transport communication\n            this.transport.removeAllListeners();\n            if (withEventListeners) {\n                if (this._beforeunloadEventListener) {\n                    removeEventListener(\"beforeunload\", this._beforeunloadEventListener, false);\n                }\n                if (this._offlineEventListener) {\n                    const i = OFFLINE_EVENT_LISTENERS.indexOf(this._offlineEventListener);\n                    if (i !== -1) {\n                        OFFLINE_EVENT_LISTENERS.splice(i, 1);\n                    }\n                }\n            }\n            // set ready state\n            this.readyState = \"closed\";\n            // clear session id\n            this.id = null;\n            // emit close event\n            this.emitReserved(\"close\", reason, description);\n            // clean buffers after, so users can still\n            // grab the buffers on `close` event\n            this.writeBuffer = [];\n            this._prevBufferLen = 0;\n        }\n    }\n}\nSocketWithoutUpgrade.protocol = protocol;\n/**\n * This class provides a WebSocket-like interface to connect to an Engine.IO server. The connection will be established\n * with one of the available low-level transports, like HTTP long-polling, WebSocket or WebTransport.\n *\n * This class comes with an upgrade mechanism, which means that once the connection is established with the first\n * low-level transport, it will try to upgrade to a better transport.\n *\n * In order to allow tree-shaking, there are no transports included, that's why the `transports` option is mandatory.\n *\n * @example\n * import { SocketWithUpgrade, WebSocket } from \"engine.io-client\";\n *\n * const socket = new SocketWithUpgrade({\n *   transports: [WebSocket]\n * });\n *\n * socket.on(\"open\", () => {\n *   socket.send(\"hello\");\n * });\n *\n * @see SocketWithoutUpgrade\n * @see Socket\n */\nexport class SocketWithUpgrade extends SocketWithoutUpgrade {\n    constructor() {\n        super(...arguments);\n        this._upgrades = [];\n    }\n    onOpen() {\n        super.onOpen();\n        if (\"open\" === this.readyState && this.opts.upgrade) {\n            for (let i = 0; i < this._upgrades.length; i++) {\n                this._probe(this._upgrades[i]);\n            }\n        }\n    }\n    /**\n     * Probes a transport.\n     *\n     * @param {String} name - transport name\n     * @private\n     */\n    _probe(name) {\n        let transport = this.createTransport(name);\n        let failed = false;\n        SocketWithoutUpgrade.priorWebsocketSuccess = false;\n        const onTransportOpen = () => {\n            if (failed)\n                return;\n            transport.send([{ type: \"ping\", data: \"probe\" }]);\n            transport.once(\"packet\", (msg) => {\n                if (failed)\n                    return;\n                if (\"pong\" === msg.type && \"probe\" === msg.data) {\n                    this.upgrading = true;\n                    this.emitReserved(\"upgrading\", transport);\n                    if (!transport)\n                        return;\n                    SocketWithoutUpgrade.priorWebsocketSuccess =\n                        \"websocket\" === transport.name;\n                    this.transport.pause(() => {\n                        if (failed)\n                            return;\n                        if (\"closed\" === this.readyState)\n                            return;\n                        cleanup();\n                        this.setTransport(transport);\n                        transport.send([{ type: \"upgrade\" }]);\n                        this.emitReserved(\"upgrade\", transport);\n                        transport = null;\n                        this.upgrading = false;\n                        this.flush();\n                    });\n                }\n                else {\n                    const err = new Error(\"probe error\");\n                    // @ts-ignore\n                    err.transport = transport.name;\n                    this.emitReserved(\"upgradeError\", err);\n                }\n            });\n        };\n        function freezeTransport() {\n            if (failed)\n                return;\n            // Any callback called by transport should be ignored since now\n            failed = true;\n            cleanup();\n            transport.close();\n            transport = null;\n        }\n        // Handle any error that happens while probing\n        const onerror = (err) => {\n            const error = new Error(\"probe error: \" + err);\n            // @ts-ignore\n            error.transport = transport.name;\n            freezeTransport();\n            this.emitReserved(\"upgradeError\", error);\n        };\n        function onTransportClose() {\n            onerror(\"transport closed\");\n        }\n        // When the socket is closed while we're probing\n        function onclose() {\n            onerror(\"socket closed\");\n        }\n        // When the socket is upgraded while we're probing\n        function onupgrade(to) {\n            if (transport && to.name !== transport.name) {\n                freezeTransport();\n            }\n        }\n        // Remove all listeners on the transport and on self\n        const cleanup = () => {\n            transport.removeListener(\"open\", onTransportOpen);\n            transport.removeListener(\"error\", onerror);\n            transport.removeListener(\"close\", onTransportClose);\n            this.off(\"close\", onclose);\n            this.off(\"upgrading\", onupgrade);\n        };\n        transport.once(\"open\", onTransportOpen);\n        transport.once(\"error\", onerror);\n        transport.once(\"close\", onTransportClose);\n        this.once(\"close\", onclose);\n        this.once(\"upgrading\", onupgrade);\n        if (this._upgrades.indexOf(\"webtransport\") !== -1 &&\n            name !== \"webtransport\") {\n            // favor WebTransport\n            this.setTimeoutFn(() => {\n                if (!failed) {\n                    transport.open();\n                }\n            }, 200);\n        }\n        else {\n            transport.open();\n        }\n    }\n    onHandshake(data) {\n        this._upgrades = this._filterUpgrades(data.upgrades);\n        super.onHandshake(data);\n    }\n    /**\n     * Filters upgrades, returning only those matching client transports.\n     *\n     * @param {Array} upgrades - server upgrades\n     * @private\n     */\n    _filterUpgrades(upgrades) {\n        const filteredUpgrades = [];\n        for (let i = 0; i < upgrades.length; i++) {\n            if (~this.transports.indexOf(upgrades[i]))\n                filteredUpgrades.push(upgrades[i]);\n        }\n        return filteredUpgrades;\n    }\n}\n/**\n * This class provides a WebSocket-like interface to connect to an Engine.IO server. The connection will be established\n * with one of the available low-level transports, like HTTP long-polling, WebSocket or WebTransport.\n *\n * This class comes with an upgrade mechanism, which means that once the connection is established with the first\n * low-level transport, it will try to upgrade to a better transport.\n *\n * @example\n * import { Socket } from \"engine.io-client\";\n *\n * const socket = new Socket();\n *\n * socket.on(\"open\", () => {\n *   socket.send(\"hello\");\n * });\n *\n * @see SocketWithoutUpgrade\n * @see SocketWithUpgrade\n */\nexport class Socket extends SocketWithUpgrade {\n    constructor(uri, opts = {}) {\n        const o = typeof uri === \"object\" ? uri : opts;\n        if (!o.transports ||\n            (o.transports && typeof o.transports[0] === \"string\")) {\n            o.transports = (o.transports || [\"polling\", \"websocket\", \"webtransport\"])\n                .map((transportName) => DEFAULT_TRANSPORTS[transportName])\n                .filter((t) => !!t);\n        }\n        super(uri, o);\n    }\n}\n", "import { Socket } from \"./socket.js\";\nexport { Socket };\nexport { SocketWithoutUpgrade, SocketWithUpgrade, } from \"./socket.js\";\nexport const protocol = Socket.protocol;\nexport { Transport, TransportError } from \"./transport.js\";\nexport { transports } from \"./transports/index.js\";\nexport { installTimerFunctions } from \"./util.js\";\nexport { parse } from \"./contrib/parseuri.js\";\nexport { nextTick } from \"./globals.node.js\";\nexport { Fetch } from \"./transports/polling-fetch.js\";\nexport { XHR as NodeXHR } from \"./transports/polling-xhr.node.js\";\nexport { XHR } from \"./transports/polling-xhr.js\";\nexport { WS as NodeWebSocket } from \"./transports/websocket.node.js\";\nexport { WS as WebSocket } from \"./transports/websocket.js\";\nexport { WT as WebTransport } from \"./transports/webtransport.js\";\n", "import { parse } from \"engine.io-client\";\n/**\n * URL parser.\n *\n * @param uri - url\n * @param path - the request path of the connection\n * @param loc - An object meant to mimic window.location.\n *        Defaults to window.location.\n * @public\n */\nexport function url(uri, path = \"\", loc) {\n    let obj = uri;\n    // default to window.location\n    loc = loc || (typeof location !== \"undefined\" && location);\n    if (null == uri)\n        uri = loc.protocol + \"//\" + loc.host;\n    // relative path support\n    if (typeof uri === \"string\") {\n        if (\"/\" === uri.charAt(0)) {\n            if (\"/\" === uri.charAt(1)) {\n                uri = loc.protocol + uri;\n            }\n            else {\n                uri = loc.host + uri;\n            }\n        }\n        if (!/^(https?|wss?):\\/\\//.test(uri)) {\n            if (\"undefined\" !== typeof loc) {\n                uri = loc.protocol + \"//\" + uri;\n            }\n            else {\n                uri = \"https://\" + uri;\n            }\n        }\n        // parse\n        obj = parse(uri);\n    }\n    // make sure we treat `localhost:80` and `localhost` equally\n    if (!obj.port) {\n        if (/^(http|ws)$/.test(obj.protocol)) {\n            obj.port = \"80\";\n        }\n        else if (/^(http|ws)s$/.test(obj.protocol)) {\n            obj.port = \"443\";\n        }\n    }\n    obj.path = obj.path || \"/\";\n    const ipv6 = obj.host.indexOf(\":\") !== -1;\n    const host = ipv6 ? \"[\" + obj.host + \"]\" : obj.host;\n    // define unique id\n    obj.id = obj.protocol + \"://\" + host + \":\" + obj.port + path;\n    // define href\n    obj.href =\n        obj.protocol +\n            \"://\" +\n            host +\n            (loc && loc.port === obj.port ? \"\" : \":\" + obj.port);\n    return obj;\n}\n", "import { Emitter } from \"@socket.io/component-emitter\";\nimport { deconstructPacket, reconstructPacket } from \"./binary.js\";\nimport { isBinary, hasBinary } from \"./is-binary.js\";\n/**\n * These strings must not be used as event names, as they have a special meaning.\n */\nconst RESERVED_EVENTS = [\n    \"connect\", // used on the client side\n    \"connect_error\", // used on the client side\n    \"disconnect\", // used on both sides\n    \"disconnecting\", // used on the server side\n    \"newListener\", // used by the Node.js EventEmitter\n    \"removeListener\", // used by the Node.js EventEmitter\n];\n/**\n * Protocol version.\n *\n * @public\n */\nexport const protocol = 5;\nexport var PacketType;\n(function (PacketType) {\n    PacketType[PacketType[\"CONNECT\"] = 0] = \"CONNECT\";\n    PacketType[PacketType[\"DISCONNECT\"] = 1] = \"DISCONNECT\";\n    PacketType[PacketType[\"EVENT\"] = 2] = \"EVENT\";\n    PacketType[PacketType[\"ACK\"] = 3] = \"ACK\";\n    PacketType[PacketType[\"CONNECT_ERROR\"] = 4] = \"CONNECT_ERROR\";\n    PacketType[PacketType[\"BINARY_EVENT\"] = 5] = \"BINARY_EVENT\";\n    PacketType[PacketType[\"BINARY_ACK\"] = 6] = \"BINARY_ACK\";\n})(PacketType || (PacketType = {}));\n/**\n * A socket.io Encoder instance\n */\nexport class Encoder {\n    /**\n     * Encoder constructor\n     *\n     * @param {function} replacer - custom replacer to pass down to JSON.parse\n     */\n    constructor(replacer) {\n        this.replacer = replacer;\n    }\n    /**\n     * Encode a packet as a single string if non-binary, or as a\n     * buffer sequence, depending on packet type.\n     *\n     * @param {Object} obj - packet object\n     */\n    encode(obj) {\n        if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {\n            if (hasBinary(obj)) {\n                return this.encodeAsBinary({\n                    type: obj.type === PacketType.EVENT\n                        ? PacketType.BINARY_EVENT\n                        : PacketType.BINARY_ACK,\n                    nsp: obj.nsp,\n                    data: obj.data,\n                    id: obj.id,\n                });\n            }\n        }\n        return [this.encodeAsString(obj)];\n    }\n    /**\n     * Encode packet as string.\n     */\n    encodeAsString(obj) {\n        // first is type\n        let str = \"\" + obj.type;\n        // attachments if we have them\n        if (obj.type === PacketType.BINARY_EVENT ||\n            obj.type === PacketType.BINARY_ACK) {\n            str += obj.attachments + \"-\";\n        }\n        // if we have a namespace other than `/`\n        // we append it followed by a comma `,`\n        if (obj.nsp && \"/\" !== obj.nsp) {\n            str += obj.nsp + \",\";\n        }\n        // immediately followed by the id\n        if (null != obj.id) {\n            str += obj.id;\n        }\n        // json data\n        if (null != obj.data) {\n            str += JSON.stringify(obj.data, this.replacer);\n        }\n        return str;\n    }\n    /**\n     * Encode packet as 'buffer sequence' by removing blobs, and\n     * deconstructing packet into object with placeholders and\n     * a list of buffers.\n     */\n    encodeAsBinary(obj) {\n        const deconstruction = deconstructPacket(obj);\n        const pack = this.encodeAsString(deconstruction.packet);\n        const buffers = deconstruction.buffers;\n        buffers.unshift(pack); // add packet info to beginning of data list\n        return buffers; // write all the buffers\n    }\n}\n/**\n * A socket.io Decoder instance\n *\n * @return {Object} decoder\n */\nexport class Decoder extends Emitter {\n    /**\n     * Decoder constructor\n     */\n    constructor(opts) {\n        super();\n        this.opts = Object.assign({\n            reviver: undefined,\n            maxAttachments: 10,\n        }, typeof opts === \"function\" ? { reviver: opts } : opts);\n    }\n    /**\n     * Decodes an encoded packet string into packet JSON.\n     *\n     * @param {String} obj - encoded packet\n     */\n    add(obj) {\n        let packet;\n        if (typeof obj === \"string\") {\n            if (this.reconstructor) {\n                throw new Error(\"got plaintext data when reconstructing a packet\");\n            }\n            packet = this.decodeString(obj);\n            const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;\n            if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {\n                packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;\n                // binary packet's json\n                this.reconstructor = new BinaryReconstructor(packet);\n                // no attachments, labeled binary but no binary data to follow\n                if (packet.attachments === 0) {\n                    super.emitReserved(\"decoded\", packet);\n                }\n            }\n            else {\n                // non-binary full packet\n                super.emitReserved(\"decoded\", packet);\n            }\n        }\n        else if (isBinary(obj) || obj.base64) {\n            // raw binary data\n            if (!this.reconstructor) {\n                throw new Error(\"got binary data when not reconstructing a packet\");\n            }\n            else {\n                packet = this.reconstructor.takeBinaryData(obj);\n                if (packet) {\n                    // received final buffer\n                    this.reconstructor = null;\n                    super.emitReserved(\"decoded\", packet);\n                }\n            }\n        }\n        else {\n            throw new Error(\"Unknown type: \" + obj);\n        }\n    }\n    /**\n     * Decode a packet String (JSON data)\n     *\n     * @param {String} str\n     * @return {Object} packet\n     */\n    decodeString(str) {\n        let i = 0;\n        // look up type\n        const p = {\n            type: Number(str.charAt(0)),\n        };\n        if (PacketType[p.type] === undefined) {\n            throw new Error(\"unknown packet type \" + p.type);\n        }\n        // look up attachments if type binary\n        if (p.type === PacketType.BINARY_EVENT ||\n            p.type === PacketType.BINARY_ACK) {\n            const start = i + 1;\n            while (str.charAt(++i) !== \"-\" && i != str.length) { }\n            const buf = str.substring(start, i);\n            if (buf != Number(buf) || str.charAt(i) !== \"-\") {\n                throw new Error(\"Illegal attachments\");\n            }\n            const n = Number(buf);\n            if (!isInteger(n) || n < 0) {\n                throw new Error(\"Illegal attachments\");\n            }\n            else if (n > this.opts.maxAttachments) {\n                throw new Error(\"too many attachments\");\n            }\n            p.attachments = n;\n        }\n        // look up namespace (if any)\n        if (\"/\" === str.charAt(i + 1)) {\n            const start = i + 1;\n            while (++i) {\n                const c = str.charAt(i);\n                if (\",\" === c)\n                    break;\n                if (i === str.length)\n                    break;\n            }\n            p.nsp = str.substring(start, i);\n        }\n        else {\n            p.nsp = \"/\";\n        }\n        // look up id\n        const next = str.charAt(i + 1);\n        if (\"\" !== next && Number(next) == next) {\n            const start = i + 1;\n            while (++i) {\n                const c = str.charAt(i);\n                if (null == c || Number(c) != c) {\n                    --i;\n                    break;\n                }\n                if (i === str.length)\n                    break;\n            }\n            p.id = Number(str.substring(start, i + 1));\n        }\n        // look up json data\n        if (str.charAt(++i)) {\n            const payload = this.tryParse(str.substr(i));\n            if (Decoder.isPayloadValid(p.type, payload)) {\n                p.data = payload;\n            }\n            else {\n                throw new Error(\"invalid payload\");\n            }\n        }\n        return p;\n    }\n    tryParse(str) {\n        try {\n            return JSON.parse(str, this.opts.reviver);\n        }\n        catch (e) {\n            return false;\n        }\n    }\n    static isPayloadValid(type, payload) {\n        switch (type) {\n            case PacketType.CONNECT:\n                return isObject(payload);\n            case PacketType.DISCONNECT:\n                return payload === undefined;\n            case PacketType.CONNECT_ERROR:\n                return typeof payload === \"string\" || isObject(payload);\n            case PacketType.EVENT:\n            case PacketType.BINARY_EVENT:\n                return (Array.isArray(payload) &&\n                    (typeof payload[0] === \"number\" ||\n                        (typeof payload[0] === \"string\" &&\n                            RESERVED_EVENTS.indexOf(payload[0]) === -1)));\n            case PacketType.ACK:\n            case PacketType.BINARY_ACK:\n                return Array.isArray(payload);\n        }\n    }\n    /**\n     * Deallocates a parser's resources\n     */\n    destroy() {\n        if (this.reconstructor) {\n            this.reconstructor.finishedReconstruction();\n            this.reconstructor = null;\n        }\n    }\n}\n/**\n * A manager of a binary event's 'buffer sequence'. Should\n * be constructed whenever a packet of type BINARY_EVENT is\n * decoded.\n *\n * @param {Object} packet\n * @return {BinaryReconstructor} initialized reconstructor\n */\nclass BinaryReconstructor {\n    constructor(packet) {\n        this.packet = packet;\n        this.buffers = [];\n        this.reconPack = packet;\n    }\n    /**\n     * Method to be called when binary data received from connection\n     * after a BINARY_EVENT packet.\n     *\n     * @param {Buffer | ArrayBuffer} binData - the raw binary data received\n     * @return {null | Object} returns null if more binary data is expected or\n     *   a reconstructed packet object if all buffers have been received.\n     */\n    takeBinaryData(binData) {\n        this.buffers.push(binData);\n        if (this.buffers.length === this.reconPack.attachments) {\n            // done with buffer list\n            const packet = reconstructPacket(this.reconPack, this.buffers);\n            this.finishedReconstruction();\n            return packet;\n        }\n        return null;\n    }\n    /**\n     * Cleans up binary packet reconstruction variables.\n     */\n    finishedReconstruction() {\n        this.reconPack = null;\n        this.buffers = [];\n    }\n}\nfunction isNamespaceValid(nsp) {\n    return typeof nsp === \"string\";\n}\n// see https://caniuse.com/mdn-javascript_builtins_number_isinteger\nconst isInteger = Number.isInteger ||\n    function (value) {\n        return (typeof value === \"number\" &&\n            isFinite(value) &&\n            Math.floor(value) === value);\n    };\nfunction isAckIdValid(id) {\n    return id === undefined || isInteger(id);\n}\n// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript\nfunction isObject(value) {\n    return Object.prototype.toString.call(value) === \"[object Object]\";\n}\nfunction isDataValid(type, payload) {\n    switch (type) {\n        case PacketType.CONNECT:\n            return payload === undefined || isObject(payload);\n        case PacketType.DISCONNECT:\n            return payload === undefined;\n        case PacketType.EVENT:\n            return (Array.isArray(payload) &&\n                (typeof payload[0] === \"number\" ||\n                    (typeof payload[0] === \"string\" &&\n                        RESERVED_EVENTS.indexOf(payload[0]) === -1)));\n        case PacketType.ACK:\n            return Array.isArray(payload);\n        case PacketType.CONNECT_ERROR:\n            return typeof payload === \"string\" || isObject(payload);\n        default:\n            return false;\n    }\n}\nexport function isPacketValid(packet) {\n    return (isNamespaceValid(packet.nsp) &&\n        isAckIdValid(packet.id) &&\n        isDataValid(packet.type, packet.data));\n}\n", "const withNativeArrayBuffer = typeof ArrayBuffer === \"function\";\nconst isView = (obj) => {\n    return typeof ArrayBuffer.isView === \"function\"\n        ? ArrayBuffer.isView(obj)\n        : obj.buffer instanceof ArrayBuffer;\n};\nconst toString = Object.prototype.toString;\nconst withNativeBlob = typeof Blob === \"function\" ||\n    (typeof Blob !== \"undefined\" &&\n        toString.call(Blob) === \"[object BlobConstructor]\");\nconst withNativeFile = typeof File === \"function\" ||\n    (typeof File !== \"undefined\" &&\n        toString.call(File) === \"[object FileConstructor]\");\n/**\n * Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File.\n *\n * @private\n */\nexport function isBinary(obj) {\n    return ((withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))) ||\n        (withNativeBlob && obj instanceof Blob) ||\n        (withNativeFile && obj instanceof File));\n}\nexport function hasBinary(obj, toJSON) {\n    if (!obj || typeof obj !== \"object\") {\n        return false;\n    }\n    if (Array.isArray(obj)) {\n        for (let i = 0, l = obj.length; i < l; i++) {\n            if (hasBinary(obj[i])) {\n                return true;\n            }\n        }\n        return false;\n    }\n    if (isBinary(obj)) {\n        return true;\n    }\n    if (obj.toJSON &&\n        typeof obj.toJSON === \"function\" &&\n        arguments.length === 1) {\n        return hasBinary(obj.toJSON(), true);\n    }\n    for (const key in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) {\n            return true;\n        }\n    }\n    return false;\n}\n", "import { isBinary } from \"./is-binary.js\";\n/**\n * Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.\n *\n * @param {Object} packet - socket.io event packet\n * @return {Object} with deconstructed packet and list of buffers\n * @public\n */\nexport function deconstructPacket(packet) {\n    const buffers = [];\n    const packetData = packet.data;\n    const pack = packet;\n    pack.data = _deconstructPacket(packetData, buffers);\n    pack.attachments = buffers.length; // number of binary 'attachments'\n    return { packet: pack, buffers: buffers };\n}\nfunction _deconstructPacket(data, buffers) {\n    if (!data)\n        return data;\n    if (isBinary(data)) {\n        const placeholder = { _placeholder: true, num: buffers.length };\n        buffers.push(data);\n        return placeholder;\n    }\n    else if (Array.isArray(data)) {\n        const newData = new Array(data.length);\n        for (let i = 0; i < data.length; i++) {\n            newData[i] = _deconstructPacket(data[i], buffers);\n        }\n        return newData;\n    }\n    else if (typeof data === \"object\" && !(data instanceof Date)) {\n        const newData = {};\n        for (const key in data) {\n            if (Object.prototype.hasOwnProperty.call(data, key)) {\n                newData[key] = _deconstructPacket(data[key], buffers);\n            }\n        }\n        return newData;\n    }\n    return data;\n}\n/**\n * Reconstructs a binary packet from its placeholder packet and buffers\n *\n * @param {Object} packet - event packet with placeholders\n * @param {Array} buffers - binary buffers to put in placeholder positions\n * @return {Object} reconstructed packet\n * @public\n */\nexport function reconstructPacket(packet, buffers) {\n    packet.data = _reconstructPacket(packet.data, buffers);\n    delete packet.attachments; // no longer useful\n    return packet;\n}\nfunction _reconstructPacket(data, buffers) {\n    if (!data)\n        return data;\n    if (data && data._placeholder === true) {\n        const isIndexValid = typeof data.num === \"number\" &&\n            data.num >= 0 &&\n            data.num < buffers.length;\n        if (isIndexValid) {\n            return buffers[data.num]; // appropriate buffer (should be natural order anyway)\n        }\n        else {\n            throw new Error(\"illegal attachments\");\n        }\n    }\n    else if (Array.isArray(data)) {\n        for (let i = 0; i < data.length; i++) {\n            data[i] = _reconstructPacket(data[i], buffers);\n        }\n    }\n    else if (typeof data === \"object\") {\n        for (const key in data) {\n            if (Object.prototype.hasOwnProperty.call(data, key)) {\n                data[key] = _reconstructPacket(data[key], buffers);\n            }\n        }\n    }\n    return data;\n}\n", "export function on(obj, ev, fn) {\n    obj.on(ev, fn);\n    return function subDestroy() {\n        obj.off(ev, fn);\n    };\n}\n", "import { PacketType } from \"socket.io-parser\";\nimport { on } from \"./on.js\";\nimport { Emitter, } from \"@socket.io/component-emitter\";\n/**\n * Internal events.\n * These events can't be emitted by the user.\n */\nconst RESERVED_EVENTS = Object.freeze({\n    connect: 1,\n    connect_error: 1,\n    disconnect: 1,\n    disconnecting: 1,\n    // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener\n    newListener: 1,\n    removeListener: 1,\n});\n/**\n * A Socket is the fundamental class for interacting with the server.\n *\n * A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate.\n *\n * @example\n * const socket = io();\n *\n * socket.on(\"connect\", () => {\n *   console.log(\"connected\");\n * });\n *\n * // send an event to the server\n * socket.emit(\"foo\", \"bar\");\n *\n * socket.on(\"foobar\", () => {\n *   // an event was received from the server\n * });\n *\n * // upon disconnection\n * socket.on(\"disconnect\", (reason) => {\n *   console.log(`disconnected due to ${reason}`);\n * });\n */\nexport class Socket extends Emitter {\n    /**\n     * `Socket` constructor.\n     */\n    constructor(io, nsp, opts) {\n        super();\n        /**\n         * Whether the socket is currently connected to the server.\n         *\n         * @example\n         * const socket = io();\n         *\n         * socket.on(\"connect\", () => {\n         *   console.log(socket.connected); // true\n         * });\n         *\n         * socket.on(\"disconnect\", () => {\n         *   console.log(socket.connected); // false\n         * });\n         */\n        this.connected = false;\n        /**\n         * Whether the connection state was recovered after a temporary disconnection. In that case, any missed packets will\n         * be transmitted by the server.\n         */\n        this.recovered = false;\n        /**\n         * Buffer for packets received before the CONNECT packet\n         */\n        this.receiveBuffer = [];\n        /**\n         * Buffer for packets that will be sent once the socket is connected\n         */\n        this.sendBuffer = [];\n        /**\n         * The queue of packets to be sent with retry in case of failure.\n         *\n         * Packets are sent one by one, each waiting for the server acknowledgement, in order to guarantee the delivery order.\n         * @private\n         */\n        this._queue = [];\n        /**\n         * A sequence to generate the ID of the {@link QueuedPacket}.\n         * @private\n         */\n        this._queueSeq = 0;\n        this.ids = 0;\n        /**\n         * A map containing acknowledgement handlers.\n         *\n         * The `withError` attribute is used to differentiate handlers that accept an error as first argument:\n         *\n         * - `socket.emit(\"test\", (err, value) => { ... })` with `ackTimeout` option\n         * - `socket.timeout(5000).emit(\"test\", (err, value) => { ... })`\n         * - `const value = await socket.emitWithAck(\"test\")`\n         *\n         * From those that don't:\n         *\n         * - `socket.emit(\"test\", (value) => { ... });`\n         *\n         * In the first case, the handlers will be called with an error when:\n         *\n         * - the timeout is reached\n         * - the socket gets disconnected\n         *\n         * In the second case, the handlers will be simply discarded upon disconnection, since the client will never receive\n         * an acknowledgement from the server.\n         *\n         * @private\n         */\n        this.acks = {};\n        this.flags = {};\n        this.io = io;\n        this.nsp = nsp;\n        if (opts && opts.auth) {\n            this.auth = opts.auth;\n        }\n        this._opts = Object.assign({}, opts);\n        if (this.io._autoConnect)\n            this.open();\n    }\n    /**\n     * Whether the socket is currently disconnected\n     *\n     * @example\n     * const socket = io();\n     *\n     * socket.on(\"connect\", () => {\n     *   console.log(socket.disconnected); // false\n     * });\n     *\n     * socket.on(\"disconnect\", () => {\n     *   console.log(socket.disconnected); // true\n     * });\n     */\n    get disconnected() {\n        return !this.connected;\n    }\n    /**\n     * Subscribe to open, close and packet events\n     *\n     * @private\n     */\n    subEvents() {\n        if (this.subs)\n            return;\n        const io = this.io;\n        this.subs = [\n            on(io, \"open\", this.onopen.bind(this)),\n            on(io, \"packet\", this.onpacket.bind(this)),\n            on(io, \"error\", this.onerror.bind(this)),\n            on(io, \"close\", this.onclose.bind(this)),\n        ];\n    }\n    /**\n     * Whether the Socket will try to reconnect when its Manager connects or reconnects.\n     *\n     * @example\n     * const socket = io();\n     *\n     * console.log(socket.active); // true\n     *\n     * socket.on(\"disconnect\", (reason) => {\n     *   if (reason === \"io server disconnect\") {\n     *     // the disconnection was initiated by the server, you need to manually reconnect\n     *     console.log(socket.active); // false\n     *   }\n     *   // else the socket will automatically try to reconnect\n     *   console.log(socket.active); // true\n     * });\n     */\n    get active() {\n        return !!this.subs;\n    }\n    /**\n     * \"Opens\" the socket.\n     *\n     * @example\n     * const socket = io({\n     *   autoConnect: false\n     * });\n     *\n     * socket.connect();\n     */\n    connect() {\n        if (this.connected)\n            return this;\n        this.subEvents();\n        if (!this.io[\"_reconnecting\"])\n            this.io.open(); // ensure open\n        if (\"open\" === this.io._readyState)\n            this.onopen();\n        return this;\n    }\n    /**\n     * Alias for {@link connect()}.\n     */\n    open() {\n        return this.connect();\n    }\n    /**\n     * Sends a `message` event.\n     *\n     * This method mimics the WebSocket.send() method.\n     *\n     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send\n     *\n     * @example\n     * socket.send(\"hello\");\n     *\n     * // this is equivalent to\n     * socket.emit(\"message\", \"hello\");\n     *\n     * @return self\n     */\n    send(...args) {\n        args.unshift(\"message\");\n        this.emit.apply(this, args);\n        return this;\n    }\n    /**\n     * Override `emit`.\n     * If the event is in `events`, it's emitted normally.\n     *\n     * @example\n     * socket.emit(\"hello\", \"world\");\n     *\n     * // all serializable datastructures are supported (no need to call JSON.stringify)\n     * socket.emit(\"hello\", 1, \"2\", { 3: [\"4\"], 5: Uint8Array.from([6]) });\n     *\n     * // with an acknowledgement from the server\n     * socket.emit(\"hello\", \"world\", (val) => {\n     *   // ...\n     * });\n     *\n     * @return self\n     */\n    emit(ev, ...args) {\n        var _a, _b, _c;\n        if (RESERVED_EVENTS.hasOwnProperty(ev)) {\n            throw new Error('\"' + ev.toString() + '\" is a reserved event name');\n        }\n        args.unshift(ev);\n        if (this._opts.retries && !this.flags.fromQueue && !this.flags.volatile) {\n            this._addToQueue(args);\n            return this;\n        }\n        const packet = {\n            type: PacketType.EVENT,\n            data: args,\n        };\n        packet.options = {};\n        packet.options.compress = this.flags.compress !== false;\n        // event ack callback\n        if (\"function\" === typeof args[args.length - 1]) {\n            const id = this.ids++;\n            const ack = args.pop();\n            this._registerAckCallback(id, ack);\n            packet.id = id;\n        }\n        const isTransportWritable = (_b = (_a = this.io.engine) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.writable;\n        const isConnected = this.connected && !((_c = this.io.engine) === null || _c === void 0 ? void 0 : _c._hasPingExpired());\n        const discardPacket = this.flags.volatile && !isTransportWritable;\n        if (discardPacket) {\n        }\n        else if (isConnected) {\n            this.notifyOutgoingListeners(packet);\n            this.packet(packet);\n        }\n        else {\n            this.sendBuffer.push(packet);\n        }\n        this.flags = {};\n        return this;\n    }\n    /**\n     * @private\n     */\n    _registerAckCallback(id, ack) {\n        var _a;\n        const timeout = (_a = this.flags.timeout) !== null && _a !== void 0 ? _a : this._opts.ackTimeout;\n        if (timeout === undefined) {\n            this.acks[id] = ack;\n            return;\n        }\n        // @ts-ignore\n        const timer = this.io.setTimeoutFn(() => {\n            delete this.acks[id];\n            for (let i = 0; i < this.sendBuffer.length; i++) {\n                if (this.sendBuffer[i].id === id) {\n                    this.sendBuffer.splice(i, 1);\n                }\n            }\n            ack.call(this, new Error(\"operation has timed out\"));\n        }, timeout);\n        const fn = (...args) => {\n            // @ts-ignore\n            this.io.clearTimeoutFn(timer);\n            ack.apply(this, args);\n        };\n        fn.withError = true;\n        this.acks[id] = fn;\n    }\n    /**\n     * Emits an event and waits for an acknowledgement\n     *\n     * @example\n     * // without timeout\n     * const response = await socket.emitWithAck(\"hello\", \"world\");\n     *\n     * // with a specific timeout\n     * try {\n     *   const response = await socket.timeout(1000).emitWithAck(\"hello\", \"world\");\n     * } catch (err) {\n     *   // the server did not acknowledge the event in the given delay\n     * }\n     *\n     * @return a Promise that will be fulfilled when the server acknowledges the event\n     */\n    emitWithAck(ev, ...args) {\n        return new Promise((resolve, reject) => {\n            const fn = (arg1, arg2) => {\n                return arg1 ? reject(arg1) : resolve(arg2);\n            };\n            fn.withError = true;\n            args.push(fn);\n            this.emit(ev, ...args);\n        });\n    }\n    /**\n     * Add the packet to the queue.\n     * @param args\n     * @private\n     */\n    _addToQueue(args) {\n        let ack;\n        if (typeof args[args.length - 1] === \"function\") {\n            ack = args.pop();\n        }\n        const packet = {\n            id: this._queueSeq++,\n            tryCount: 0,\n            pending: false,\n            args,\n            flags: Object.assign({ fromQueue: true }, this.flags),\n        };\n        args.push((err, ...responseArgs) => {\n            if (packet !== this._queue[0]) {\n            }\n            const hasError = err !== null;\n            if (hasError) {\n                if (packet.tryCount > this._opts.retries) {\n                    this._queue.shift();\n                    if (ack) {\n                        ack(err);\n                    }\n                }\n            }\n            else {\n                this._queue.shift();\n                if (ack) {\n                    ack(null, ...responseArgs);\n                }\n            }\n            packet.pending = false;\n            return this._drainQueue();\n        });\n        this._queue.push(packet);\n        this._drainQueue();\n    }\n    /**\n     * Send the first packet of the queue, and wait for an acknowledgement from the server.\n     * @param force - whether to resend a packet that has not been acknowledged yet\n     *\n     * @private\n     */\n    _drainQueue(force = false) {\n        if (!this.connected || this._queue.length === 0) {\n            return;\n        }\n        const packet = this._queue[0];\n        if (packet.pending && !force) {\n            return;\n        }\n        packet.pending = true;\n        packet.tryCount++;\n        this.flags = packet.flags;\n        this.emit.apply(this, packet.args);\n    }\n    /**\n     * Sends a packet.\n     *\n     * @param packet\n     * @private\n     */\n    packet(packet) {\n        packet.nsp = this.nsp;\n        this.io._packet(packet);\n    }\n    /**\n     * Called upon engine `open`.\n     *\n     * @private\n     */\n    onopen() {\n        if (typeof this.auth == \"function\") {\n            this.auth((data) => {\n                this._sendConnectPacket(data);\n            });\n        }\n        else {\n            this._sendConnectPacket(this.auth);\n        }\n    }\n    /**\n     * Sends a CONNECT packet to initiate the Socket.IO session.\n     *\n     * @param data\n     * @private\n     */\n    _sendConnectPacket(data) {\n        this.packet({\n            type: PacketType.CONNECT,\n            data: this._pid\n                ? Object.assign({ pid: this._pid, offset: this._lastOffset }, data)\n                : data,\n        });\n    }\n    /**\n     * Called upon engine or manager `error`.\n     *\n     * @param err\n     * @private\n     */\n    onerror(err) {\n        if (!this.connected) {\n            this.emitReserved(\"connect_error\", err);\n        }\n    }\n    /**\n     * Called upon engine `close`.\n     *\n     * @param reason\n     * @param description\n     * @private\n     */\n    onclose(reason, description) {\n        this.connected = false;\n        delete this.id;\n        this.emitReserved(\"disconnect\", reason, description);\n        this._clearAcks();\n    }\n    /**\n     * Clears the acknowledgement handlers upon disconnection, since the client will never receive an acknowledgement from\n     * the server.\n     *\n     * @private\n     */\n    _clearAcks() {\n        Object.keys(this.acks).forEach((id) => {\n            const isBuffered = this.sendBuffer.some((packet) => String(packet.id) === id);\n            if (!isBuffered) {\n                // note: handlers that do not accept an error as first argument are ignored here\n                const ack = this.acks[id];\n                delete this.acks[id];\n                if (ack.withError) {\n                    ack.call(this, new Error(\"socket has been disconnected\"));\n                }\n            }\n        });\n    }\n    /**\n     * Called with socket packet.\n     *\n     * @param packet\n     * @private\n     */\n    onpacket(packet) {\n        const sameNamespace = packet.nsp === this.nsp;\n        if (!sameNamespace)\n            return;\n        switch (packet.type) {\n            case PacketType.CONNECT:\n                if (packet.data && packet.data.sid) {\n                    this.onconnect(packet.data.sid, packet.data.pid);\n                }\n                else {\n                    this.emitReserved(\"connect_error\", new Error(\"It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)\"));\n                }\n                break;\n            case PacketType.EVENT:\n            case PacketType.BINARY_EVENT:\n                this.onevent(packet);\n                break;\n            case PacketType.ACK:\n            case PacketType.BINARY_ACK:\n                this.onack(packet);\n                break;\n            case PacketType.DISCONNECT:\n                this.ondisconnect();\n                break;\n            case PacketType.CONNECT_ERROR:\n                this.destroy();\n                const err = new Error(packet.data.message);\n                // @ts-ignore\n                err.data = packet.data.data;\n                this.emitReserved(\"connect_error\", err);\n                break;\n        }\n    }\n    /**\n     * Called upon a server event.\n     *\n     * @param packet\n     * @private\n     */\n    onevent(packet) {\n        const args = packet.data || [];\n        if (null != packet.id) {\n            args.push(this.ack(packet.id));\n        }\n        if (this.connected) {\n            this.emitEvent(args);\n        }\n        else {\n            this.receiveBuffer.push(Object.freeze(args));\n        }\n    }\n    emitEvent(args) {\n        if (this._anyListeners && this._anyListeners.length) {\n            const listeners = this._anyListeners.slice();\n            for (const listener of listeners) {\n                listener.apply(this, args);\n            }\n        }\n        super.emit.apply(this, args);\n        if (this._pid && args.length && typeof args[args.length - 1] === \"string\") {\n            this._lastOffset = args[args.length - 1];\n        }\n    }\n    /**\n     * Produces an ack callback to emit with an event.\n     *\n     * @private\n     */\n    ack(id) {\n        const self = this;\n        let sent = false;\n        return function (...args) {\n            // prevent double callbacks\n            if (sent)\n                return;\n            sent = true;\n            self.packet({\n                type: PacketType.ACK,\n                id: id,\n                data: args,\n            });\n        };\n    }\n    /**\n     * Called upon a server acknowledgement.\n     *\n     * @param packet\n     * @private\n     */\n    onack(packet) {\n        const ack = this.acks[packet.id];\n        if (typeof ack !== \"function\") {\n            return;\n        }\n        delete this.acks[packet.id];\n        // @ts-ignore FIXME ack is incorrectly inferred as 'never'\n        if (ack.withError) {\n            packet.data.unshift(null);\n        }\n        // @ts-ignore\n        ack.apply(this, packet.data);\n    }\n    /**\n     * Called upon server connect.\n     *\n     * @private\n     */\n    onconnect(id, pid) {\n        this.id = id;\n        this.recovered = pid && this._pid === pid;\n        this._pid = pid; // defined only if connection state recovery is enabled\n        this.connected = true;\n        this.emitBuffered();\n        this._drainQueue(true);\n        this.emitReserved(\"connect\");\n    }\n    /**\n     * Emit buffered events (received and emitted).\n     *\n     * @private\n     */\n    emitBuffered() {\n        this.receiveBuffer.forEach((args) => this.emitEvent(args));\n        this.receiveBuffer = [];\n        this.sendBuffer.forEach((packet) => {\n            this.notifyOutgoingListeners(packet);\n            this.packet(packet);\n        });\n        this.sendBuffer = [];\n    }\n    /**\n     * Called upon server disconnect.\n     *\n     * @private\n     */\n    ondisconnect() {\n        this.destroy();\n        this.onclose(\"io server disconnect\");\n    }\n    /**\n     * Called upon forced client/server side disconnections,\n     * this method ensures the manager stops tracking us and\n     * that reconnections don't get triggered for this.\n     *\n     * @private\n     */\n    destroy() {\n        if (this.subs) {\n            // clean subscriptions to avoid reconnections\n            this.subs.forEach((subDestroy) => subDestroy());\n            this.subs = undefined;\n        }\n        this.io[\"_destroy\"](this);\n    }\n    /**\n     * Disconnects the socket manually. In that case, the socket will not try to reconnect.\n     *\n     * If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed.\n     *\n     * @example\n     * const socket = io();\n     *\n     * socket.on(\"disconnect\", (reason) => {\n     *   // console.log(reason); prints \"io client disconnect\"\n     * });\n     *\n     * socket.disconnect();\n     *\n     * @return self\n     */\n    disconnect() {\n        if (this.connected) {\n            this.packet({ type: PacketType.DISCONNECT });\n        }\n        // remove socket from pool\n        this.destroy();\n        if (this.connected) {\n            // fire events\n            this.onclose(\"io client disconnect\");\n        }\n        return this;\n    }\n    /**\n     * Alias for {@link disconnect()}.\n     *\n     * @return self\n     */\n    close() {\n        return this.disconnect();\n    }\n    /**\n     * Sets the compress flag.\n     *\n     * @example\n     * socket.compress(false).emit(\"hello\");\n     *\n     * @param compress - if `true`, compresses the sending data\n     * @return self\n     */\n    compress(compress) {\n        this.flags.compress = compress;\n        return this;\n    }\n    /**\n     * Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not\n     * ready to send messages.\n     *\n     * @example\n     * socket.volatile.emit(\"hello\"); // the server may or may not receive it\n     *\n     * @returns self\n     */\n    get volatile() {\n        this.flags.volatile = true;\n        return this;\n    }\n    /**\n     * Sets a modifier for a subsequent event emission that the callback will be called with an error when the\n     * given number of milliseconds have elapsed without an acknowledgement from the server:\n     *\n     * @example\n     * socket.timeout(5000).emit(\"my-event\", (err) => {\n     *   if (err) {\n     *     // the server did not acknowledge the event in the given delay\n     *   }\n     * });\n     *\n     * @returns self\n     */\n    timeout(timeout) {\n        this.flags.timeout = timeout;\n        return this;\n    }\n    /**\n     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n     * callback.\n     *\n     * @example\n     * socket.onAny((event, ...args) => {\n     *   console.log(`got ${event}`);\n     * });\n     *\n     * @param listener\n     */\n    onAny(listener) {\n        this._anyListeners = this._anyListeners || [];\n        this._anyListeners.push(listener);\n        return this;\n    }\n    /**\n     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n     * callback. The listener is added to the beginning of the listeners array.\n     *\n     * @example\n     * socket.prependAny((event, ...args) => {\n     *   console.log(`got event ${event}`);\n     * });\n     *\n     * @param listener\n     */\n    prependAny(listener) {\n        this._anyListeners = this._anyListeners || [];\n        this._anyListeners.unshift(listener);\n        return this;\n    }\n    /**\n     * Removes the listener that will be fired when any event is emitted.\n     *\n     * @example\n     * const catchAllListener = (event, ...args) => {\n     *   console.log(`got event ${event}`);\n     * }\n     *\n     * socket.onAny(catchAllListener);\n     *\n     * // remove a specific listener\n     * socket.offAny(catchAllListener);\n     *\n     * // or remove all listeners\n     * socket.offAny();\n     *\n     * @param listener\n     */\n    offAny(listener) {\n        if (!this._anyListeners) {\n            return this;\n        }\n        if (listener) {\n            const listeners = this._anyListeners;\n            for (let i = 0; i < listeners.length; i++) {\n                if (listener === listeners[i]) {\n                    listeners.splice(i, 1);\n                    return this;\n                }\n            }\n        }\n        else {\n            this._anyListeners = [];\n        }\n        return this;\n    }\n    /**\n     * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,\n     * e.g. to remove listeners.\n     */\n    listenersAny() {\n        return this._anyListeners || [];\n    }\n    /**\n     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n     * callback.\n     *\n     * Note: acknowledgements sent to the server are not included.\n     *\n     * @example\n     * socket.onAnyOutgoing((event, ...args) => {\n     *   console.log(`sent event ${event}`);\n     * });\n     *\n     * @param listener\n     */\n    onAnyOutgoing(listener) {\n        this._anyOutgoingListeners = this._anyOutgoingListeners || [];\n        this._anyOutgoingListeners.push(listener);\n        return this;\n    }\n    /**\n     * Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the\n     * callback. The listener is added to the beginning of the listeners array.\n     *\n     * Note: acknowledgements sent to the server are not included.\n     *\n     * @example\n     * socket.prependAnyOutgoing((event, ...args) => {\n     *   console.log(`sent event ${event}`);\n     * });\n     *\n     * @param listener\n     */\n    prependAnyOutgoing(listener) {\n        this._anyOutgoingListeners = this._anyOutgoingListeners || [];\n        this._anyOutgoingListeners.unshift(listener);\n        return this;\n    }\n    /**\n     * Removes the listener that will be fired when any event is emitted.\n     *\n     * @example\n     * const catchAllListener = (event, ...args) => {\n     *   console.log(`sent event ${event}`);\n     * }\n     *\n     * socket.onAnyOutgoing(catchAllListener);\n     *\n     * // remove a specific listener\n     * socket.offAnyOutgoing(catchAllListener);\n     *\n     * // or remove all listeners\n     * socket.offAnyOutgoing();\n     *\n     * @param [listener] - the catch-all listener (optional)\n     */\n    offAnyOutgoing(listener) {\n        if (!this._anyOutgoingListeners) {\n            return this;\n        }\n        if (listener) {\n            const listeners = this._anyOutgoingListeners;\n            for (let i = 0; i < listeners.length; i++) {\n                if (listener === listeners[i]) {\n                    listeners.splice(i, 1);\n                    return this;\n                }\n            }\n        }\n        else {\n            this._anyOutgoingListeners = [];\n        }\n        return this;\n    }\n    /**\n     * Returns an array of listeners that are listening for any event that is specified. This array can be manipulated,\n     * e.g. to remove listeners.\n     */\n    listenersAnyOutgoing() {\n        return this._anyOutgoingListeners || [];\n    }\n    /**\n     * Notify the listeners for each packet sent\n     *\n     * @param packet\n     *\n     * @private\n     */\n    notifyOutgoingListeners(packet) {\n        if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) {\n            const listeners = this._anyOutgoingListeners.slice();\n            for (const listener of listeners) {\n                listener.apply(this, packet.data);\n            }\n        }\n    }\n}\n", "/**\n * Initialize backoff timer with `opts`.\n *\n * - `min` initial timeout in milliseconds [100]\n * - `max` max timeout [10000]\n * - `jitter` [0]\n * - `factor` [2]\n *\n * @param {Object} opts\n * @api public\n */\nexport function Backoff(opts) {\n    opts = opts || {};\n    this.ms = opts.min || 100;\n    this.max = opts.max || 10000;\n    this.factor = opts.factor || 2;\n    this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0;\n    this.attempts = 0;\n}\n/**\n * Return the backoff duration.\n *\n * @return {Number}\n * @api public\n */\nBackoff.prototype.duration = function () {\n    var ms = this.ms * Math.pow(this.factor, this.attempts++);\n    if (this.jitter) {\n        var rand = Math.random();\n        var deviation = Math.floor(rand * this.jitter * ms);\n        ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;\n    }\n    return Math.min(ms, this.max) | 0;\n};\n/**\n * Reset the number of attempts.\n *\n * @api public\n */\nBackoff.prototype.reset = function () {\n    this.attempts = 0;\n};\n/**\n * Set the minimum duration\n *\n * @api public\n */\nBackoff.prototype.setMin = function (min) {\n    this.ms = min;\n};\n/**\n * Set the maximum duration\n *\n * @api public\n */\nBackoff.prototype.setMax = function (max) {\n    this.max = max;\n};\n/**\n * Set the jitter\n *\n * @api public\n */\nBackoff.prototype.setJitter = function (jitter) {\n    this.jitter = jitter;\n};\n", "import { Socket as Engine, installTimerFunctions, nextTick, } from \"engine.io-client\";\nimport { Socket } from \"./socket.js\";\nimport * as parser from \"socket.io-parser\";\nimport { on } from \"./on.js\";\nimport { Backoff } from \"./contrib/backo2.js\";\nimport { Emitter, } from \"@socket.io/component-emitter\";\nexport class Manager extends Emitter {\n    constructor(uri, opts) {\n        var _a;\n        super();\n        this.nsps = {};\n        this.subs = [];\n        if (uri && \"object\" === typeof uri) {\n            opts = uri;\n            uri = undefined;\n        }\n        opts = opts || {};\n        opts.path = opts.path || \"/socket.io\";\n        this.opts = opts;\n        installTimerFunctions(this, opts);\n        this.reconnection(opts.reconnection !== false);\n        this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);\n        this.reconnectionDelay(opts.reconnectionDelay || 1000);\n        this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);\n        this.randomizationFactor((_a = opts.randomizationFactor) !== null && _a !== void 0 ? _a : 0.5);\n        this.backoff = new Backoff({\n            min: this.reconnectionDelay(),\n            max: this.reconnectionDelayMax(),\n            jitter: this.randomizationFactor(),\n        });\n        this.timeout(null == opts.timeout ? 20000 : opts.timeout);\n        this._readyState = \"closed\";\n        this.uri = uri;\n        const _parser = opts.parser || parser;\n        this.encoder = new _parser.Encoder();\n        this.decoder = new _parser.Decoder();\n        this._autoConnect = opts.autoConnect !== false;\n        if (this._autoConnect)\n            this.open();\n    }\n    reconnection(v) {\n        if (!arguments.length)\n            return this._reconnection;\n        this._reconnection = !!v;\n        if (!v) {\n            this.skipReconnect = true;\n        }\n        return this;\n    }\n    reconnectionAttempts(v) {\n        if (v === undefined)\n            return this._reconnectionAttempts;\n        this._reconnectionAttempts = v;\n        return this;\n    }\n    reconnectionDelay(v) {\n        var _a;\n        if (v === undefined)\n            return this._reconnectionDelay;\n        this._reconnectionDelay = v;\n        (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMin(v);\n        return this;\n    }\n    randomizationFactor(v) {\n        var _a;\n        if (v === undefined)\n            return this._randomizationFactor;\n        this._randomizationFactor = v;\n        (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setJitter(v);\n        return this;\n    }\n    reconnectionDelayMax(v) {\n        var _a;\n        if (v === undefined)\n            return this._reconnectionDelayMax;\n        this._reconnectionDelayMax = v;\n        (_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMax(v);\n        return this;\n    }\n    timeout(v) {\n        if (!arguments.length)\n            return this._timeout;\n        this._timeout = v;\n        return this;\n    }\n    /**\n     * Starts trying to reconnect if reconnection is enabled and we have not\n     * started reconnecting yet\n     *\n     * @private\n     */\n    maybeReconnectOnOpen() {\n        // Only try to reconnect if it's the first time we're connecting\n        if (!this._reconnecting &&\n            this._reconnection &&\n            this.backoff.attempts === 0) {\n            // keeps reconnection from firing twice for the same reconnection loop\n            this.reconnect();\n        }\n    }\n    /**\n     * Sets the current transport `socket`.\n     *\n     * @param {Function} fn - optional, callback\n     * @return self\n     * @public\n     */\n    open(fn) {\n        if (~this._readyState.indexOf(\"open\"))\n            return this;\n        this.engine = new Engine(this.uri, this.opts);\n        const socket = this.engine;\n        const self = this;\n        this._readyState = \"opening\";\n        this.skipReconnect = false;\n        // emit `open`\n        const openSubDestroy = on(socket, \"open\", function () {\n            self.onopen();\n            fn && fn();\n        });\n        const onError = (err) => {\n            this.cleanup();\n            this._readyState = \"closed\";\n            this.emitReserved(\"error\", err);\n            if (fn) {\n                fn(err);\n            }\n            else {\n                // Only do this if there is no fn to handle the error\n                this.maybeReconnectOnOpen();\n            }\n        };\n        // emit `error`\n        const errorSub = on(socket, \"error\", onError);\n        if (false !== this._timeout) {\n            const timeout = this._timeout;\n            // set timer\n            const timer = this.setTimeoutFn(() => {\n                openSubDestroy();\n                onError(new Error(\"timeout\"));\n                socket.close();\n            }, timeout);\n            if (this.opts.autoUnref) {\n                timer.unref();\n            }\n            this.subs.push(() => {\n                this.clearTimeoutFn(timer);\n            });\n        }\n        this.subs.push(openSubDestroy);\n        this.subs.push(errorSub);\n        return this;\n    }\n    /**\n     * Alias for open()\n     *\n     * @return self\n     * @public\n     */\n    connect(fn) {\n        return this.open(fn);\n    }\n    /**\n     * Called upon transport open.\n     *\n     * @private\n     */\n    onopen() {\n        // clear old subs\n        this.cleanup();\n        // mark as open\n        this._readyState = \"open\";\n        this.emitReserved(\"open\");\n        // add new subs\n        const socket = this.engine;\n        this.subs.push(on(socket, \"ping\", this.onping.bind(this)), on(socket, \"data\", this.ondata.bind(this)), on(socket, \"error\", this.onerror.bind(this)), on(socket, \"close\", this.onclose.bind(this)), \n        // @ts-ignore\n        on(this.decoder, \"decoded\", this.ondecoded.bind(this)));\n    }\n    /**\n     * Called upon a ping.\n     *\n     * @private\n     */\n    onping() {\n        this.emitReserved(\"ping\");\n    }\n    /**\n     * Called with data.\n     *\n     * @private\n     */\n    ondata(data) {\n        try {\n            this.decoder.add(data);\n        }\n        catch (e) {\n            this.onclose(\"parse error\", e);\n        }\n    }\n    /**\n     * Called when parser fully decodes a packet.\n     *\n     * @private\n     */\n    ondecoded(packet) {\n        // the nextTick call prevents an exception in a user-provided event listener from triggering a disconnection due to a \"parse error\"\n        nextTick(() => {\n            this.emitReserved(\"packet\", packet);\n        }, this.setTimeoutFn);\n    }\n    /**\n     * Called upon socket error.\n     *\n     * @private\n     */\n    onerror(err) {\n        this.emitReserved(\"error\", err);\n    }\n    /**\n     * Creates a new socket for the given `nsp`.\n     *\n     * @return {Socket}\n     * @public\n     */\n    socket(nsp, opts) {\n        let socket = this.nsps[nsp];\n        if (!socket) {\n            socket = new Socket(this, nsp, opts);\n            this.nsps[nsp] = socket;\n        }\n        else if (this._autoConnect && !socket.active) {\n            socket.connect();\n        }\n        return socket;\n    }\n    /**\n     * Called upon a socket close.\n     *\n     * @param socket\n     * @private\n     */\n    _destroy(socket) {\n        const nsps = Object.keys(this.nsps);\n        for (const nsp of nsps) {\n            const socket = this.nsps[nsp];\n            if (socket.active) {\n                return;\n            }\n        }\n        this._close();\n    }\n    /**\n     * Writes a packet.\n     *\n     * @param packet\n     * @private\n     */\n    _packet(packet) {\n        const encodedPackets = this.encoder.encode(packet);\n        for (let i = 0; i < encodedPackets.length; i++) {\n            this.engine.write(encodedPackets[i], packet.options);\n        }\n    }\n    /**\n     * Clean up transport subscriptions and packet buffer.\n     *\n     * @private\n     */\n    cleanup() {\n        this.subs.forEach((subDestroy) => subDestroy());\n        this.subs.length = 0;\n        this.decoder.destroy();\n    }\n    /**\n     * Close the current socket.\n     *\n     * @private\n     */\n    _close() {\n        this.skipReconnect = true;\n        this._reconnecting = false;\n        this.onclose(\"forced close\");\n    }\n    /**\n     * Alias for close()\n     *\n     * @private\n     */\n    disconnect() {\n        return this._close();\n    }\n    /**\n     * Called when:\n     *\n     * - the low-level engine is closed\n     * - the parser encountered a badly formatted packet\n     * - all sockets are disconnected\n     *\n     * @private\n     */\n    onclose(reason, description) {\n        var _a;\n        this.cleanup();\n        (_a = this.engine) === null || _a === void 0 ? void 0 : _a.close();\n        this.backoff.reset();\n        this._readyState = \"closed\";\n        this.emitReserved(\"close\", reason, description);\n        if (this._reconnection && !this.skipReconnect) {\n            this.reconnect();\n        }\n    }\n    /**\n     * Attempt a reconnection.\n     *\n     * @private\n     */\n    reconnect() {\n        if (this._reconnecting || this.skipReconnect)\n            return this;\n        const self = this;\n        if (this.backoff.attempts >= this._reconnectionAttempts) {\n            this.backoff.reset();\n            this.emitReserved(\"reconnect_failed\");\n            this._reconnecting = false;\n        }\n        else {\n            const delay = this.backoff.duration();\n            this._reconnecting = true;\n            const timer = this.setTimeoutFn(() => {\n                if (self.skipReconnect)\n                    return;\n                this.emitReserved(\"reconnect_attempt\", self.backoff.attempts);\n                // check again for the case socket closed in above events\n                if (self.skipReconnect)\n                    return;\n                self.open((err) => {\n                    if (err) {\n                        self._reconnecting = false;\n                        self.reconnect();\n                        this.emitReserved(\"reconnect_error\", err);\n                    }\n                    else {\n                        self.onreconnect();\n                    }\n                });\n            }, delay);\n            if (this.opts.autoUnref) {\n                timer.unref();\n            }\n            this.subs.push(() => {\n                this.clearTimeoutFn(timer);\n            });\n        }\n    }\n    /**\n     * Called upon successful reconnect.\n     *\n     * @private\n     */\n    onreconnect() {\n        const attempt = this.backoff.attempts;\n        this._reconnecting = false;\n        this.backoff.reset();\n        this.emitReserved(\"reconnect\", attempt);\n    }\n}\n", "import { url } from \"./url.js\";\nimport { Manager } from \"./manager.js\";\nimport { Socket } from \"./socket.js\";\n/**\n * Managers cache.\n */\nconst cache = {};\nfunction lookup(uri, opts) {\n    if (typeof uri === \"object\") {\n        opts = uri;\n        uri = undefined;\n    }\n    opts = opts || {};\n    const parsed = url(uri, opts.path || \"/socket.io\");\n    const source = parsed.source;\n    const id = parsed.id;\n    const path = parsed.path;\n    const sameNamespace = cache[id] && path in cache[id][\"nsps\"];\n    const newConnection = opts.forceNew ||\n        opts[\"force new connection\"] ||\n        false === opts.multiplex ||\n        sameNamespace;\n    let io;\n    if (newConnection) {\n        io = new Manager(source, opts);\n    }\n    else {\n        if (!cache[id]) {\n            cache[id] = new Manager(source, opts);\n        }\n        io = cache[id];\n    }\n    if (parsed.query && !opts.query) {\n        opts.query = parsed.queryKey;\n    }\n    return io.socket(parsed.path, opts);\n}\n// so that \"lookup\" can be used both as a function (e.g. `io(...)`) and as a\n// namespace (e.g. `io.connect(...)`), for backward compatibility\nObject.assign(lookup, {\n    Manager,\n    Socket,\n    io: lookup,\n    connect: lookup,\n});\n/**\n * Protocol version.\n *\n * @public\n */\nexport { protocol } from \"socket.io-parser\";\n/**\n * Expose constructors for standalone build.\n *\n * @public\n */\nexport { Manager, Socket, lookup as io, lookup as connect, lookup as default, };\nexport { Fetch, NodeXHR, XHR, NodeWebSocket, WebSocket, WebTransport, } from \"engine.io-client\";\n", "// @ts-nocheck\n/** Define the base component extensions for other components in this package.\n * Used to ensure that standard properties and methods are available in every component.\n *\n * Version: See the class code\n *\n */\n/** Copyright (c) 2024-2025 Julian Knight (Totally Information)\n * https://it.knightnet.org.uk, https://github.com/TotallyInformation\n *\n * Licensed under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an 'AS IS' BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** Namespace\n * @namespace Library\n */\n\n/**\n * @class\n * @augments HTMLElement\n * @description Define the base component extensions for other components in this package.\n *\n * @element ti-base-component\n * @memberOf Library\n\n * STANDARD METHODS:\n  * @function config Update runtime configuration, return complete config\n  * @function createShadowSelectors Creates the jQuery-like $ and $$ methods\n  * @function deepAssign Object deep merger\n  * @function doInheritStyles If requested, add link to an external style sheet\n  * @function ensureId Adds a unique ID to the tag if no ID defined.\n  * @function uibSend Send a message to the Node-RED server via uibuilder if available.\n  * @function _uibMsgHandler Not yet in use\n  * @function _event (name,data) Standardised custom event dispatcher\n  * @function _ready Call from end of connectedCallback. Sets connected prop and outputs events\n\n * Standard watched attributes (common across all my components):\n  * @property {string|boolean} inherit-style - Optional. Load external styles into component (only useful if using template). If present but empty, will default to './index.css'. Optionally give a URL to load.\n\n * Standard props (common across all my components):\n  * @property {string} baseVersion Static. The component version string (date updated). Also has a getter.\n  * @property {number} _iCount Static. The count of instances of this component that weren't given an id. Creates a unique id as needed.\n  * @property {boolean} uib True if UIBUILDER for Node-RED is loaded\n  * @property {object} uibuilder Reference to loaded UIBUILDER for Node-RED client library if loaded (else undefined)\n  * @property {function(string): Element} $ jQuery-like shadow dom selector\n  * @property {function(string): NodeList} $$  jQuery-like shadow dom multi-selector\n  * @property {boolean} connected False until connectedCallback finishes\n  * @property {string} name Placeholder for the optional name attribute\n  * @property {object} opts This components controllable options - get/set using the `config()` method\n  *\n  * @property {string} version Getter that returns the class version & baseVersion static strings.\n\n * Other props:\n  * By default, all attributes are also created as properties\n\n * See https://github.com/runem/web-component-analyzer?tab=readme-ov-file#-how-to-document-your-components-using-jsdoc\n */\n\n// Guard allows this module to be imported in Node.js/SSR contexts (e.g. for\n// components that expose a pure renderToHTML export) without a DOM being present.\n// In a browser, HTMLElement is always defined so behaviour is unchanged.\nconst _HTMLElement = typeof HTMLElement !== 'undefined' ? HTMLElement : class {}\n\nclass TiBaseComponent extends _HTMLElement {\n    /** Component version */\n    static baseVersion = '2025-09-20'\n\n    /** Holds a count of how many instances of this component are on the page that don't have their own id\n     * Used to ensure a unique id if needing to add one dynamically\n     */\n    static _iCount = 0\n\n    /** Is UIBUILDER for Node-RED loaded? */\n    uib = !!window['uibuilder']\n    uibuilder = window['uibuilder']\n\n    /** Mini jQuery-like shadow dom selector (see constructor)\n     * @type {function(string): Element}\n     * @param {string} selector - A CSS selector to match the element within the shadow DOM.\n     * @returns {Element} The first element that matches the specified selector.\n     */\n    $\n    /** Mini jQuery-like shadow dom multi-selector (see constructor)\n     * @type {function(string): NodeList}\n     * @param {string} selector - A CSS selector to match the element within the shadow DOM.\n     * @returns {NodeList} A STATIC list of all shadow dom elements that match the selector.\n     */\n    $$\n\n    /** True when instance finishes connecting.\n     * Allows initial calls of attributeChangedCallback to be\n     * ignored if needed.\n     */\n    connected = false\n\n    /** Placeholder for the optional name attribute @type {string} */\n    name\n\n    /** Runtime configuration settings @type {object} */\n    opts = {}\n\n    /** Report the current component version string\n     * @returns {string} The component version & base version as a string\n     */\n    static get version() {\n        // @ts-ignore\n        return `${this.componentVersion} (Base: ${this.baseVersion})`\n    }\n\n    // get id() {\n    //     return this.id\n    // }\n\n    // set id(value) {\n    //     // this.id = value\n    //     console.log('>> SETTING ID:', value, this.id, this.getAttribute('id'))\n    // }\n\n\n    /** NB: Attributes not available here - use connectedCallback to reference */\n    constructor() {\n        super()\n    }\n\n    /** OPTIONAL. Update runtime configuration, return complete config\n     * @param {object|undefined} config If present, partial or full set of options. If undefined, fn returns the current full option settings\n     * @returns {object} The full set of options\n     */\n    config(config) {\n        // Merge config but ensure that default states always present\n        // if (config) this.opts = { ...this.opts, ...config }\n        if (config) this.opts = TiBaseComponent.deepAssign(this.opts, config)\n        return this.opts\n    }\n\n    /** Creates the $ and $$ fns that do css selections against the shadow dom */\n    createShadowSelectors() {\n        this.$ = this.shadowRoot?.querySelector.bind(this.shadowRoot)\n        this.$$ = this.shadowRoot?.querySelectorAll.bind(this.shadowRoot)\n    }\n\n    /** Utility object deep merge fn\n     * @param {object} target Merge target object\n     * @param  {...object} sources 1 or more source objects to merge\n     * @returns {object} Deep merged object\n     */\n    static deepAssign(target, ...sources) {\n        for (let source of sources) { // eslint-disable-line prefer-const\n            for (let k in source) { // eslint-disable-line prefer-const\n                const vs = source[k]\n                const vt = target[k]\n                if (Object(vs) == vs && Object(vt) === vt) {\n                    target[k] = TiBaseComponent.deepAssign(vt, vs)\n                    continue\n                }\n                target[k] = source[k]\n            }\n        }\n        return target\n    }\n\n    /** Optionally apply an external linked style sheet for Shadow DOM (called from connectedCallback)\n     * param {*} url The URL for the linked style sheet\n     */\n    async doInheritStyles() {\n        if (!this.shadowRoot) return\n        if (!this.hasAttribute('inherit-style')) return\n\n        let url = this.getAttribute('inherit-style')\n        if (!url) url = './index.css'\n\n        const linkEl = document.createElement('link')\n        linkEl.setAttribute('type', 'text/css')\n        linkEl.setAttribute('rel', 'stylesheet')\n        linkEl.setAttribute('href', url)\n        this.shadowRoot.appendChild(linkEl)\n\n        console.info(`[${this.localName}] Inherit-style requested. Loading: \"${url}\"`)\n    }\n\n    /** Ensure that the component instance has a unique ID & check again if uib loaded */\n    ensureId() {\n        // Check again if UIBUILDER for Node-RED is loaded\n        this.uib = !!window['uibuilder']\n\n        if (!this.id) {\n            // if (!this.name) this.name = this.getAttribute('name')\n            // if (this.name) this.id = this.name.toLowerCase().replace(/\\s/g, '_')\n            // else this.id = `${this.localName}-${++this.constructor._iCount}`\n            // @ts-ignore\n            this.id = `${this.localName}-${++this.constructor._iCount}`\n        }\n    }\n\n    /** Check if slot has meaningful content (not just whitespace)\n     * @returns {boolean} True if slot has non-empty content\n     */\n    hasSlotContent() {\n        const slot = this.shadowRoot.querySelector('slot')\n        const assignedNodes = slot.assignedNodes()\n\n        return assignedNodes.some(node => {\n            if (node.nodeType === Node.ELEMENT_NODE) {\n                return true\n            }\n            if (node.nodeType === Node.TEXT_NODE) {\n                return node.textContent.trim().length > 0\n            }\n            return false\n        })\n    }\n\n    /** Attaches a new stylesheet before all other stylesheets in the light DOM\n     * @param {string} cssText - CSS text to inject directly\n     * @param {number} order - Optional order/priority for stylesheet placement. Lower numbers = higher priority (inserted first). Defaults to 0.\n     * @returns {Element} The created or existing style element\n     * @throws {Error} If cssText is not provided\n     * @example\n     * // Inject CSS text directly with default order\n     * dataList.prependStylesheet('.custom { color: hsl(0, 100%, 50%); }')\n     *\n     * // Inject CSS with specific order (lower number = higher priority)\n     * dataList.prependStylesheet('.base { font-size: 1rem; }', 1)\n     * dataList.prependStylesheet('.critical { color: hsl(0, 100%, 50%); }', 0)\n     */\n    prependStylesheet(cssText, order = 0) {\n        if (!cssText) {\n            throw new Error(`[${this.localName}] cssText must be provided`)\n        }\n\n        // TODO: - Add ability to append after other stylesheets (including those in the HTML head)\n\n        // Check if same stylesheet already exists\n        const existingStylesheet = this._findExistingStylesheet()\n        // If so, return existing element instead of creating duplicate\n        if (existingStylesheet) return existingStylesheet\n\n        // Create style element with direct CSS text\n        const styleElement = document.createElement('style')\n        styleElement.textContent = cssText\n        styleElement.setAttribute('data-component', this.localName)\n        styleElement.setAttribute('data-order', order.toString())\n\n        // Prepend to light DOM (document head) with order consideration\n        this._prependToDocumentHead(styleElement, order)\n        return styleElement\n    }\n\n    /** Send a message to the Node-RED server via uibuilder if available\n     * NB: These web components are NEVER dependent on Node-RED or uibuilder.\n     * @param {string} evtName The event name to send\n     * @param {*} data The data to send\n     */\n    uibSend(evtName, data){\n        if (this.uib) {\n            if (this.uibuilder.ioConnected) {\n                this.uibuilder.send({\n                    topic: `${this.localName}:${evtName}`,\n                    payload: data,\n                    id: this.id,\n                    name: this.name,\n                })\n            } else {\n                console.warn(`[${this.localName}] uibuilder not connected to server, cannot send:`, evtName, data)\n            }\n        }\n    }\n\n    // #region ---- Methods private to extended classes ----\n    // These are called from a class that extends this base class but should not be called directly by the user.\n\n    /** Standardised connection. Call from the start of connectedCallback fn */\n    _connect() {\n        // Make sure instance has an ID. Create an id from name or calculation if needed\n        this.ensureId()  // in base class\n        // Apply parent styles from a stylesheet if required - only required if using an applied template\n        this.doInheritStyles()  // in base class\n\n        // Listen for a uibuilder msg that is targetted at this instance of the component\n        if (this.uib) this.uibuilder.onTopic(`${this.localName}::${this.id}`, this._uibMsgHandler.bind(this) )\n    }\n\n    /** Standardised constructor. Keep after call to super()\n     * @param {Node|string} template Nodes/string content that will be cloned into the shadow dom\n     * @param {{mode:'open'|'closed',delegatesFocus:boolean}=} shadowOpts Options passed to attachShadow\n     */\n    _construct(template, shadowOpts) {\n        if (!template) return\n        if (!shadowOpts) shadowOpts = { mode: 'open', delegatesFocus: true, }\n        // Only attach the shadow dom if code and style isolation is needed\n        this.attachShadow(shadowOpts)\n            .append(template)\n\n        // jQuery-like selectors but for the shadow. NB: Returns are STATIC not dynamic lists\n        this.createShadowSelectors()  // in base class\n    }\n\n    /** Standardised disconnection. Call from the END of disconnectedCallback fn */\n    _disconnect() {\n        // @ts-ignore Remove optional uibuilder event listener\n        document.removeEventListener(`uibuilder:msg:_ui:update:${this.id}`, this._uibMsgHandler )\n\n        // Keep at end. Let everyone know that an instance of the component has been disconnected\n        this._event('disconnected')\n    }\n\n    /** Custom event dispacher `component-name:name` with detail data\n     * @example\n     *   this._event('ready')\n     * @example\n     *   this._event('ready', {age: 42, type: 'android'})\n     *\n     * @param {string} evtName A name to give the event, added to the component-name separated with a :\n     * @param {*=} data Optional data object to pass to event listeners via the evt.detail property\n     */\n    _event(evtName, data) {\n        this.dispatchEvent(new CustomEvent(`${this.localName}:${evtName}`, {\n            bubbles: true,\n            composed: true,\n            detail: {\n                id: this.id,\n                name: this.name,\n                data: data,\n            },\n        } ) )\n    }\n\n    /** Call from end of connectedCallback */\n    _ready() {\n        this.connected = true\n        this._event('connected')\n        this._event('ready')\n    }\n\n    /** Handle a `${this.localName}::${this.id}` custom event\n     * Each prop in the msg.payload is set as a prop on the component instance.\n     * @param {object} msg A uibuilder message object\n     */\n    _uibMsgHandler(msg) {\n        // if msg.payload is not an object, ignore\n        if (typeof msg.payload !== 'object') {\n            console.warn(`[${this.localName}] Ignoring msg, payload is not an object:`, msg)\n            return\n        }\n\n        // set properties from the msg\n        Object.keys(msg.payload).forEach(key => {\n            if (key.startsWith('_')) return\n            let key2 = key.toLowerCase()\n            if (key2.startsWith('data-')) key2 = 'data' // special case\n            switch (key2) {\n                case 'value': {\n                    this.setAttribute('value', msg.payload[key])\n                    break\n                }\n\n                case 'class': {\n                    this.className = msg.payload[key]\n                    break\n                }\n\n                case 'style': {\n                    this.style.cssText = msg.payload[key]\n                    break\n                }\n\n                case 'data': {\n                    this.dataset[key.replace('data-', '')] = msg.payload[key]\n                    break\n                }\n\n                default: {\n                    this[key] = msg.payload[key]\n                    break\n                }\n            }\n        })\n    }\n\n    // #endregion ---- Methods private to the extended classes ----\n\n    // #region ---- Methods private to the base class only ----\n\n    /** Find existing component stylesheet with the same data-component attribute value\n     * Assumes that the style element has a `data-component` attribute set to the component's local name\n     * @returns {Element|null} Existing element or null if not found\n     * @private\n     */\n    _findExistingStylesheet() {\n        const existing = document.head.querySelector(\n            `style[data-component=\"${this.localName}\"]`\n        )\n        return existing\n    }\n\n    /** Helper method to prepend a style element to the document head with order consideration\n     * @param {HTMLElement} styleElement - The style element to prepend\n     * @param {number} order - The order/priority for placement (lower numbers = higher priority)\n     * @private\n     */\n    _prependToDocumentHead(styleElement, order) {\n        const head = document.head\n\n        // Find existing injected stylesheets to determine proper insertion point\n        const existingComponentStyles = Array.from(head.querySelectorAll('style[data-component]'))\n\n        if (existingComponentStyles.length === 0) {\n            // No existing injected styles, insert at the very beginning\n            const firstChild = head.firstChild\n            if (firstChild) {\n                head.insertBefore(styleElement, firstChild)\n            } else {\n                head.appendChild(styleElement)\n            }\n            return\n        }\n\n        // Find the correct position based on order\n        let insertBefore = null\n        for (const existing of existingComponentStyles) {\n            const existingOrder = parseInt(existing.getAttribute('data-order') ?? '0', 10)\n            if (order < existingOrder) {\n                insertBefore = existing\n                break\n            }\n        }\n\n        if (insertBefore) {\n            // Insert before the found element\n            head.insertBefore(styleElement, insertBefore)\n        } else {\n            // Insert after all existing component styles but before non-component styles\n            const lastInjected = existingComponentStyles[existingComponentStyles.length - 1]\n            const nextSibling = lastInjected.nextSibling\n            if (nextSibling) {\n                head.insertBefore(styleElement, nextSibling)\n            } else {\n                head.appendChild(styleElement)\n            }\n        }\n    }\n\n    // #endregion ---- Methods private to the base class only ----\n} // ---- end of Class ---- //\n\n// Make the class the default export so it can be used elsewhere\nexport default TiBaseComponent\n\n// This is a library class so don't self-register, it is only for inclusion in actual components\n", "/* eslint-disable jsdoc/check-tag-names */\n/* eslint-disable jsdoc/valid-types */\n// @ts-nocheck\n/** A zero dependency web component that will display a managed uibuilder variable.\n *\n * Version: See component version\n */\n/*\n  Copyright (c) 2023-2026 Julian Knight (Totally Information)\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n*/\n\n/** TODO\n * - Move other attrib change processing to setters\n */\n\nimport TiBaseComponent from './ti-base-component.mjs'\n\n// const template = document.createElement('template')\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`<span></span>`\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`<link type=\"text/css\" rel=\"stylesheet\" href=\"\"../uibuilder/uib-brand.min.css\"\" media=\"all\"><span></span>`\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`\n// {/* <style>@import url(\"../uibuilder/uib-brand.min.css\");</style><span></span> */}\n// `\n\n/** Namespace\n * @namespace Live\n */\n\n/**\n * @class\n * @augments TiBaseComponent\n * @description Define a new zero dependency custom web component will display a managed uibuilder variable.\n *\n * @element uib-var\n * @memberOf Live\n\n * METHODS FROM BASE: (see TiBaseComponent)\n * STANDARD METHODS:\n  * @function attributeChangedCallback Called when an attribute is added, removed, updated or replaced\n  * @function connectedCallback Called when the element is added to a document\n  * @function constructor Construct the component\n  * @function disconnectedCallback Called when the element is removed from a document\n\n * OTHER METHODS:\n  * None\n\n * CUSTOM EVENTS:\n  * @fires uib-var:connected - When an instance of the component is attached to the DOM. `evt.details` contains the details of the element.\n  * @fires uib-var:ready - Alias for connected. The instance can handle property & attribute changes\n  * @fires uib-var:disconnected - When an instance of the component is removed from the DOM. `evt.details` contains the details of the element.\n  * @fires uib-var:attribChanged - When a watched attribute changes. `evt.details.data` contains the details of the change.\n  * NOTE that listeners can be attached either to the `document` or to the specific element instance.\n\n * Standard watched attributes (common across all my components):\n  * @attr {string|boolean} inherit-style - Optional. Load external styles into component (only useful if using template). If present but empty, will default to './index.css'. Optionally give a URL to load.\n  * @attr {string} name - Optional. HTML name attribute. Included in output _meta prop.\n\n * Other watched attributes:\n  * @attr {string} data-before - Optional. Text to show before the variable value.\n  * @attr {string} data-after - Optional. Text to show after the variable value.\n  * @attr {string} filter - Optional. A function name which will be applied to the variable value before display. Can include arguments in parentheses (e.g. `myFilter(1, 'abc')`). The function can be a global function or a function on the uibuilder client instance (e.g. `uibuilder.get`).\n\n * PROPS FROM BASE: (see TiBaseComponent)\n * OTHER STANDARD PROPS:\n  * @property {string} componentVersion Static. The component version string (date updated). Also has a getter that returns component and base version strings.\n\n * Other props:\n  * By default, all attributes are also created as properties\n\n * @slot Default content display.\n\n * @example\n  * <uib-var name=\"var01\" topic=\"mytopic\"></uib-var>\n  * <uib-var name=\"var02\" variable=\"msg.payload\"></uib-var>\n  * <uib-var name=\"var03\" variable=\"msg.payload\" type=\"json\"></uib-var>\n  * <uib-var name=\"var04\" variable=\"msg.payload\" filter=\"uibuilder.get('msg.payload')\"></uib-var>\n  * <uib-var name=\"var04\" variable=\"msg.payload\" data-before=\"Status: \" data-after=\". \"></uib-var>\n\n * @see https://totallyinformation.github.io/node-red-contrib-uibuilder/#/client-docs/custom-components?id=uib-var\n\n * See https://github.com/runem/web-component-analyzer?tab=readme-ov-file#-how-to-document-your-components-using-jsdoc\n */\nclass UibVar extends TiBaseComponent {\n    /** Component version */\n    static componentVersion = '2026-02-15'\n\n    /** Makes HTML attribute change watched\n     * @returns {Array<string>} List of all of the html attribs (props) listened to\n     */\n    static get observedAttributes() {\n        return [\n            // Standard watched attributes:\n            /* 'inherit-style', */ 'name',\n            // Other watched attributes:\n            'filter', 'id', 'report',\n            'topic', 'type', 'undefined', 'variable',\n        ]\n    }\n\n    // #region --- Class Properties ---\n\n    /** Name of the uibuilder mangaged variable to use @type {string} */\n    #variable\n    /** Current value of the watched variable */\n    value\n    /** Holds reference to var watch callback so it can be cancelled @type {Function} */\n    #varCb\n    /** The watched msg topic @type {string} */\n    #topic\n    /** Holds reference to topic watch callback so it can be cancelled @type {Function} */\n    #topicCb\n    /** Whether to output if the variable is undefined */\n    undef = false\n    /** Whether to send update value to Node-RED on change */\n    report = false\n    /** What is the value type */\n    type = 'plain'\n    /** what are the available types? */\n    types = ['plain', 'html', 'markdown', 'object', 'json', 'table', 'list', 'array']\n\n    // #endregion --- Class Properties ---\n\n    constructor() {\n        super()\n        // Only attach the shadow dom if code and style isolation is needed - comment out if shadow dom not required\n        // if (template && template.content) this._construct(template.content.cloneNode(true))\n    }\n\n    /** Set the uibuilder variable name to watch */\n    set variable(varName) {\n        this.#variable = varName\n        this.splitVarName\n        if (varName) {\n            // console.log('resolving', this.resolveVariable(varName))\n            try {\n                this.splitVarName = varName.split(/[\\.\\[\\]\\'\\\"]/)\n                this.#variable = varName = this.splitVarName.shift()\n            } catch (e) {\n                throw new Error(`[${this.localName}] variable attribute: Name split failed on \"${varName}\". ${e.message}`)\n            }\n        }\n\n        // Stop any previous variable or topic settings\n        if (this.#varCb) this.uibuilder.cancelChange(varName, this.#varCb)\n\n        if (!varName) return\n\n        // Set the initial value immediately - this handles the case where the variable was already set before this component was connected to the DOM\n        this._varChange(this.uibuilder.get(varName))\n\n        // Watch for changes in the variable (could use `uibuilder:propertyChanged:${prop}` event instead)\n        this.#varCb = this.uibuilder.onChange(varName, this._varChange.bind(this))\n    }\n\n    /** Get the watched uibuilder variable name\n     * @returns {string} The watched variable name\n     */\n    get variable() {\n        return this.#variable\n    }\n\n    /** Set the uibuilder msg topic to watch. We could use `uibuilder:msg:topic:${msg.topic}` event instead */\n    set topic(topicName) {\n        this.#topic = topicName\n        // Stop any previous variable or topic settings\n        if (this.#topicCb) this.uibuilder.cancelTopic(topicName, this.#topicCb)\n\n        // Handle empty topic\n        if (!topicName) return\n\n        // Set up a uibuilder listener for this topic - ASSUMES msg.payload contains the VALUE to show\n        this.#topicCb = this.uibuilder.onTopic(topicName, this._topicChange.bind(this))\n    }\n\n    /** Get the watched uibuilder msg topic\n     * @returns {string} The watched topic name\n     */\n    get topic() {\n        return this.#topic\n    }\n\n    // Runs when an instance is added to the DOM\n    connectedCallback() {\n        this._connect() // Keep at start.\n\n        // Initial process of key attributes\n        this.variable = this.getAttribute('variable')\n        this.topic = this.getAttribute('topic')\n\n        this._ready() // Keep at end. Let everyone know that a new instance of the component has been connected & is ready\n    }\n\n    // Runs when an instance is removed from the DOM\n    disconnectedCallback() {\n        // Stop any previous variable or topic settings\n        if (this.#varCb) this.uibuilder.cancelChange(this.#variable, this.#varCb)\n        if (this.#topicCb) {\n            this.uibuilder.cancelTopic(this.#topic, this.#topicCb)\n\n            Object.keys(this.#topicCb).forEach( (topic) => {\n                this.uibuilder.cancelTopic(topic, this.#topicCb[topic])\n            })\n        }\n\n        this._disconnect() // Keep at end.\n    }\n\n    /** Handle watched attributes\n     * NOTE: On initial startup, this is called for each watched attrib set in HTML - BEFORE connectedCallback is called.\n     * Attribute values can only ever be strings\n     * @param {string} attrib The name of the attribute that is changing\n     * @param {string} oldVal The old value of the attribute\n     * @param {string} newVal The new value of the attribute\n     */\n    attributeChangedCallback(attrib, oldVal, newVal) {\n        /** Optionally ignore attrib changes until instance is fully connected\n         * Otherwise this can fire BEFORE everthing is fully connected.\n         */\n        // if (!this.connected) return\n\n        // Don't bother if the new value same as old\n        if ( oldVal === newVal ) return\n        // Create a property from the value - WARN: Be careful with name clashes - triggers setters\n        this[attrib] = newVal\n\n        // Add other dynamic attribute processing here.\n        // If attribute processing doesn't need to be dynamic, process in connectedCallback as that happens earlier in the lifecycle\n        switch (attrib) {\n            case 'undefined': {\n                if (newVal === '' || ['on', 'true', 'report'].includes(newVal.toLowerCase())) this.undef = true\n                else this.undef = false\n                break\n            }\n            case 'report': {\n                if (newVal === '' || ['on', 'true', 'report'].includes(newVal.toLowerCase())) this.report = true\n                else this.report = false\n                break\n            }\n            case 'type': {\n                if (newVal === '' || !this.types.includes(newVal.toLowerCase())) this.type = 'plain'\n                else this.type = newVal\n                break\n            }\n            case 'filter': {\n                this.filter = undefined\n                this.filterArgs = []\n\n                // Handle empty filter\n                if (!newVal) break\n\n                this.filter = newVal\n\n                // Filter the input - at least limit the length of the attr\n                newVal = newVal.slice(0, 127)\n                // Remove spaces and then separate fn name from potential extra arguments\n                const f = newVal.replace(/\\s/g, '').match(/([a-zA-Z_$][a-zA-Z_$0-9.-]+)(\\((.*)\\))?/)\n                if (!f) {\n                    console.warn(`\u26A0\uFE0F [uib-var] Filter function \"${newVal}\" invalid. Cannot process.`)\n                    break\n                }\n                // Fn name\n                this.filter = f[1]\n                // Fn arguments\n                if (f[3]) { // undefined if no args found\n                    // TODO Do we really want to try this?\n                    try {\n                        this.filterArgs = JSON.parse(f[3])\n                    } catch (e) {}\n\n                    this.filterArgs = f[3].split(',').map((x) => {\n                        // No objects/arrays allowed - if they have a , they are split\n                        x = x.trim()\n                        // @ts-ignore NB: Do NOT use Number.isNaN here, it is too narrow minded\n                        if (isNaN(x)) {\n                            // String inside string ends up double quoted so remove those\n                            let y = x.replace(/^[\"'`]/, '').replace(/[\"'`]$/, '')\n                            // Attempt very limited parse in case it is valid object/array\n                            try {\n                                y = new Function(`return ${y}`)()\n                            } catch (e) {}\n                            return y\n                        }\n                        return Number(x)\n                    })\n                }\n\n                // Apply the filter directly if neither variable nor topic attribs set\n                if (!this.variable && !this.topic) this.showVar(false)\n                break\n            }\n\n            default: {\n                break\n            }\n        }\n\n        // Keep at end. Let everyone know that an attribute has changed for this instance of the component\n        this._event('attribChanged', { attribute: attrib, newVal: newVal, oldVal: oldVal, })\n    } // --- end of attributeChangedCallback --- //\n\n    /** Process watched uibuilder variable value change\n     * @param {*} value The value of the managed uibuilder variable\n     */\n    _varChange(value) {\n        // If varname was nested object - get the real value - silently exit if the path can't be traversed (found)\n        let success = true\n        if (this.splitVarName.length > 0) {\n            let target = value\n            const partSuccess = []\n            try {\n                this.splitVarName.forEach( (part) => {\n                    let successPart\n                    if (target[part] === undefined) successPart = false\n                    else successPart = true\n                    partSuccess.push(successPart)\n                    target = target[part]\n                })\n                value = target\n                success = partSuccess.filter(Boolean).length > 0 ? true : false\n            } catch (e) {\n                success = false\n            }\n        }\n        if (success) {\n            this.value = value\n            this.showVar()\n            if (this.report === true) this.uibuilder.send({ topic: this.variable, payload: this.value || undefined, source: this.localName, id: this.id, })\n        }\n    }\n\n    /** Process watched uibuilder msg.topic received\n     * @param {object} msg The value of the managed uibuilder variable\n     */\n    _topicChange(msg) {\n        this.uibuilder.log('trace', this.localName, `Topic msg received: '${msg.topic}'`, msg)\n        // console.log('\uD83D\uDD26 topicMonitor \u27EB', newVal, msg)\n        this.value = msg.payload\n        this.showVar()\n        if (this.report === true) this.uibuilder.send({ topic: msg.topic, payload: this.value || undefined, source: this.localName, id: this.id, })\n    }\n\n    /** Convert this.value to DOM output (applies output filter if needed)\n     * @param {boolean} chkVal If true (default), check for undefined value. False used to run filter even with no value set.\n     */\n    showVar(chkVal = true) {\n        this.uibuilder.log('trace', this.localName, `showVar. chkVal: '${chkVal}'. Value=`, this.value)\n\n        // If user doesn't want to show undefined vars, allow the component slot to show instead\n        if (chkVal === true && this.value === undefined && this.undef !== true) {\n            // this.shadow.innerHTML = '<slot></slot>'\n            return\n        }\n\n        // Apply the filter to the value before display\n        let val = chkVal ? this.doFilter(this.value) : this.doFilter()\n\n        // console.log('\uD83D\uDD26 varDOM \u27EB ', val, typeof val, this.type)\n\n        let out = val\n\n        switch (this.type) {\n            case 'markdown': {\n                if (this.uib) out = this.uibuilder.convertMarkdown(val)\n                break\n            }\n\n            case 'json':\n            case 'object': {\n                // console.log(this.uibuilder.syntaxHighlight(val))\n                out = `<pre class=\"syntax-highlight\">${this.uib ? this.uibuilder.syntaxHighlight(val) : val}</pre>`\n                break\n            }\n\n            case 'table': {\n                // console.log('\uD83D\uDD26 val \u27EB', val)\n                // if (!Array.isArray(val)) {\n                //     out = '<code>Contents of msg.payload is not an array which is required for table output.</code>'\n                //     break\n                // }\n                out = this.uibuilder.buildHtmlTable(val).outerHTML\n                break\n            }\n\n            case 'array':\n            case 'list': {\n                if (!Array.isArray(val)) val = [val]\n                // console.log('\uD83D\uDD26 val \u27EB', val)\n                out = '<ul>'\n                val.forEach( (li) => {\n                    out += `<li>${li}</li>`\n                })\n                out += '</ul>'\n                break\n            }\n\n            case 'plain': {\n                // get the plain text version of the value by using DOM conversion\n                const div = document.createElement('div')\n                div.innerHTML = val\n                out = div.textContent\n                // NB: Deliberately fall through to html/default\n            }\n            case 'html':\n            default: {\n                const t = typeof val\n                // @ts-ignore\n                if (Array.isArray(val) || t === '[object Object]' || t === 'object') {\n                    try {\n                        out = JSON.stringify(val)\n                    } catch (e) {}\n                }\n                break\n            }\n        }\n\n        // Add before and after text if specified\n        if (this.dataset.before) out = `${this.dataset.before}${out}`\n        if (this.dataset.after) out = `${out}${this.dataset.after}`\n\n        // if (this.uib) this.shadow.innerHTML = this.uibuilder.sanitiseHTML(out)\n        // else this.shadow.innerHTML = out\n        if (this.uib) this.innerHTML = this.uibuilder.sanitiseHTML(out)\n        else this.innerHTML = out\n\n        // this.shadow.appendChild(this.css)\n    }\n\n    /** Apply value filter if specified\n     * @param {*} value The value to change\n     * @returns {*} The amended value that will be displayed\n     */\n    doFilter(value) {\n        if (this.filter) {\n            // Cater for dotted notation functions (e.g. uibuilder.get)\n            const splitFilter = this.filter.split('.')\n            let globalFn = globalThis[splitFilter[0]]\n            if (globalFn && splitFilter.length > 1) {\n                const parts = [splitFilter.pop()]\n                parts.forEach( (part) => {\n                    globalFn = globalFn[part]\n                } )\n            }\n            if (!globalFn && this.uib === true) globalFn = this.uibuilder[splitFilter[0]]\n            if (globalFn && typeof globalFn !== 'function' ) globalFn = undefined\n            if (globalFn) {\n                const argList = value === undefined ? [...this.filterArgs] : [value, ...this.filterArgs]\n                value = Reflect.apply(globalFn, value ?? globalFn, argList)\n            } else {\n                console.warn(`\u26A0\uFE0F [uib-var] Filter function \"${this.filter}\" ${typeof globalFn === 'object' ? 'is an object not a function' : 'not found'}`)\n            }\n        }\n\n        return value\n    }\n}\n\n// Make the class the default export so it can be used elsewhere\nexport default UibVar\n\n/** Self register the class to global\n * Enables new data lists to be dynamically added via JS\n * and lets the static methods be called\n */\nwindow['UibVar'] = UibVar\n\n// Add the class as a new Custom Element to the window object - Done by uibuilder client library otherwise uibuilder fns can't be used\n// customElements.define('uib-var', UibVar)\n", "/* eslint-disable jsdoc/valid-types */\n/** A zero dependency web component that will display some metadata about the current web page.\n */\n/*\n  Copyright (c) 2024-2025 Julian Knight (Totally Information)\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n*/\n\nimport TiBaseComponent from './ti-base-component.mjs'\n\n// const template = document.createElement('template')\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`<span></span>`\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`<link type=\"text/css\" rel=\"stylesheet\" href=\"\"../uibuilder/uib-brand.min.css\"\" media=\"all\"><span></span>`\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`\n// {/* <style>@import url(\"../uibuilder/uib-brand.min.css\");</style><span></span> */}\n// `\n\n/** Namespace\n * @namespace Live\n */\n\n/**\n * @class\n * @augments TiBaseComponent\n * @description Define a new zero dependency custom web component ECMA module that can be used as an HTML tag\n *\n * @element component-template\n * @memberOf Live\n\n * METHODS FROM BASE:\n  * @function config Update runtime configuration, return complete config\n  * @function createShadowSelectors Creates the jQuery-like $ and $$ methods\n  * @function deepAssign Object deep merger\n  * @function doInheritStyles If requested, add link to an external style sheet\n  * @function ensureId Adds a unique ID to the tag if no ID defined.\n  * @function _connect Call from start of connectedCallback. Sets connected prop and creates shadow selectors\n  * @function _event(name,data) Standardised custom event dispatcher\n  * @function _disconnect Call from end of disconnectedCallback. Clears connected prop and removes shadow selectors\n  * @function _ready Call from end of connectedCallback. Sets connected prop and outputs events\n  * @function _uibMsgHandler Not yet in use\n * STANDARD METHODS:\n  * @function attributeChangedCallback Called when an attribute is added, removed, updated or replaced\n  * @function connectedCallback Called when the element is added to a document\n  * @function constructor Construct the component\n  * @function disconnectedCallback Called when the element is removed from a document\n\n * OTHER METHODS:\n  * @function doFilter Apply value filter if specified\n  * @function doFormat(val,type) Format a value using this.format\n  * @function doWatch Process changes to the required uibuilder variable\n  * @function varDom(chkVal) Convert this.value to DOM output (applies output filter if needed)\n\n * CUSTOM EVENTS:\n  * @fires component-template:connected - When an instance of the component is attached to the DOM. `evt.details` contains the details of the element.\n  * @fires component-template:ready - Alias for connected. The instance can handle property & attribute changes\n  * @fires component-template:disconnected - When an instance of the component is removed from the DOM. `evt.details` contains the details of the element.\n  * @fires component-template:attribChanged - When a watched attribute changes. `evt.details.data` contains the details of the change.\n  * NOTE that listeners can be attached either to the `document` or to the specific element instance.\n\n * @class\n  * @throws {Error} Throws an error if the uibuilder client library is not available.\n\n * Standard watched attributes (common across all my components):\n  * @attr {string|boolean} inherit-style - Optional. Load external styles into component (only useful if using template). If present but empty, will default to './index.css'. Optionally give a URL to load.\n  * @attr {string} name - Optional. HTML name attribute. Included in output _meta prop.\n\n * Other watched attributes:\n  * @attr {string} format - Optional. Format to apply to the output. Default is none. Options are 'd', 'dt', 't', 'k', 'm'\n  * @attr {string} type - Optional. What type of metadata to display. Default is 'created'. Options are 'created', 'updated', 'crup', 'both', 'size', 'modified', 'all'\n\n * PROPS FROM BASE:\n  * @property {number} _iCount Static. The component version string (date updated)\n  * @property {boolean} uib True if UIBUILDER for Node-RED is loaded\n  * @property {object} uibuilder Reference to loaded UIBUILDER for Node-RED client library if loaded (else undefined)\n  * @property {function(string): Element} $ jQuery-like shadow dom selector (or undefined if shadow dom not used)\n  * @property {function(string): NodeList} $$  jQuery-like shadow dom multi-selector (or undefined if shadow dom not used)\n  * @property {boolean} connected False until connectedCallback finishes\n  * @property {string} name Placeholder for the optional name attribute\n  * @property {object} opts This components controllable options - get/set using the `config()` method - empty object by default\n  * @property {string} baseVersion Static. The base component version string (date updated).\n * OTHER STANDARD PROPS:\n  * @property {string} componentVersion Static. The component version string (date updated). Also has a getter that returns component and base version strings.\n\n * Other props:\n  * @property {string} format - Chosen formatting - default to none\n  * @property {'d'|'dt'|'t'|'k'|'m'} formats - what are the available formats?\n  * @property {boolean} report - Whether to send update value to Node-RED on change. Default is false\n  * @property {object} topicMonitors - Holds uibuilder.onTopic listeners\n  * @property {string} type - What is the value type. Default is 'created'\n  * @property {'created'|'updated'|'crup'|'both'| 'size'|'modified'|'all'} types - what are the available types?\n  * @property {boolean} undef - Whether to output if the variable is undefined. Default is false\n  * @property {*} value - Current value of the watched variable\n  * @property {string} variable - Name of the uibuilder managed variable to use. Default is 'pageMeta'\n  * By default, all attributes are also created as properties\n\n * @slot Container contents\n\n * See https://github.com/runem/web-component-analyzer?tab=readme-ov-file#-how-to-document-your-components-using-jsdoc\n\n * @example\n  *  <div id=\"more\">\n  *    <uib-meta type=\"created\" format=\"t\"></uib-meta><br>\n  *    <uib-meta format=\"d\"></uib-meta><br>\n  *    <uib-meta type=\"updated\" format=\"dt\"></uib-meta><br>\n  *    <uib-meta type=\"crup\" format=\"d\"></uib-meta><br>\n  *    <uib-meta type=\"size\" format=\"k\"></uib-meta><br>\n  *  </div>\n */\nclass UibMeta extends TiBaseComponent {\n    /** Component version */\n    static componentVersion = '2025-01-06'\n\n    // #region --- Class Properties ---\n\n    /** @type {string} Name of the uibuilder mangaged variable to use */\n    variable = 'pageMeta'\n    /** Current value of the watched variable */\n    value\n    /** Whether to output if the variable is undefined */\n    undef = false\n    /** Whether to send update value to Node-RED on change */\n    report = false\n    /** What is the value type */\n    type = 'created'\n    /** what are the available types? */\n    types = ['created', 'updated', 'crup', 'both', 'size', 'modified', 'all']\n    /** Chosen formatting - default to none */\n    format = ''\n    /** what are the available formats? */\n    formats = ['d', 'dt', 't', 'k', 'm']\n    /** Holds uibuilder.onTopic listeners */\n    topicMonitors = {}\n\n    // Makes HTML attribute change watched\n    static get observedAttributes() {\n        return [\n            // Standard watched attributes:\n            'inherit-style', 'name',\n            // Other watched attributes:\n            'type', 'format',\n        ]\n    }\n\n    // #endregion --- Class Properties ---\n\n    constructor() {\n        super()\n        this.shadow = this.attachShadow({ mode: 'open', delegatesFocus: true, })\n        //  .append(template.content.cloneNode(true))\n\n        this.$ = this.shadowRoot.querySelector.bind(this.shadowRoot)\n\n        // Apply external styles to the shadow dom - assumes you use index.css in same url location as main url\n        // this.css = document.createElement('link')\n        // this.css.setAttribute('type', 'text/css')\n        // this.css.setAttribute('rel', 'stylesheet')\n        // this.css.setAttribute('href', './index.css')\n\n        if (!this.uibuilder) throw new Error('[uib-meta] uibuilder client library not available')\n\n        // Get the latest page metadata from the server\n        this.value = this.uibuilder.get('pageMeta')\n        if (!this.value) this.uibuilder.getPageMeta()\n        this.doWatch()\n    }\n\n    // Runs when an instance is added to the DOM\n    connectedCallback() {\n        this._connect() // Keep at start.\n\n        this._ready() // Keep at end. Let everyone know that a new instance of the component has been connected & is ready\n    }\n\n    // Runs when an instance is removed from the DOM\n    disconnectedCallback() {\n        this._disconnect() // Keep at end.\n    }\n\n    /** Handle watched attributes\n     * NOTE: On initial startup, this is called for each watched attrib set in HTML - BEFORE connectedCallback is called.\n     * Attribute values can only ever be strings\n     * @param {string} attrib The name of the attribute that is changing\n     * @param {string} oldVal The old value of the attribute\n     * @param {string} newVal The new value of the attribute\n     */\n    attributeChangedCallback(attrib, oldVal, newVal) {\n        /** Optionally ignore attrib changes until instance is fully connected\n         * Otherwise this can fire BEFORE everthing is fully connected.\n         */\n        // if (!this.connected) return\n\n        // Don't bother if the new value same as old\n        if ( oldVal === newVal ) return\n        // Create a property from the value - WARN: Be careful with name clashes\n        // this[attrib] = newVal\n\n        // Add other dynamic attribute processing here.\n        // If attribute processing doesn't need to be dynamic, process in connectedCallback as that happens earlier in the lifecycle\n        switch (attrib) {\n            case 'type': {\n                if (newVal === '' || !this.types.includes(newVal.toLowerCase())) this.type = 'created'\n                else this.type = newVal\n                break\n            }\n\n            case 'format': {\n                if (!this.formats.includes(newVal.toLowerCase())) this.type = ''\n                else this[attrib] = newVal\n                break\n            }\n\n            default: {\n                this[attrib] = newVal\n                break\n            }\n        }\n\n        // Keep at end. Let everyone know that an attribute has changed for this instance of the component\n        this._event('attribChanged', { attribute: attrib, newVal: newVal, oldVal: oldVal, })\n    }\n\n    /** Process changes to the required uibuilder variable */\n    doWatch() {\n        // if (!this.variable) throw new Error('No variable name provided')\n        // if (!this.uib) throw new Error('UIBUILDER client library not loaded - this component must be loaded AFTER the UIBUILDER library')\n\n        // this.value = window['uibuilder'].get(this.variable)\n        this.varDom()\n\n        // Watch for changes in the variable\n        window['uibuilder'].onChange(this.variable, (val) => {\n            this.value = val\n            this.varDom()\n            if (this.report === true) window['uibuilder'].send({ topic: this.variable, payload: this.value || undefined, })\n        })\n    }\n\n    /** Convert this.value to DOM output (applies output filter if needed)\n     * @param {boolean} chkVal If true (default), check for undefined value. False used to run filter even with no value set.\n     */\n    varDom(chkVal = true) {\n        // If user doesn't want to show undefined vars, allow the component slot to show instead\n        if (chkVal === true && !this.value && this.undef !== true) {\n            this.shadow.innerHTML = '<slot></slot>'\n            return\n        }\n\n        // Apply the filter to the value before display\n        // const val = chkVal ? this.doFilter(this.value) : this.doFilter()\n\n        // console.log('\uD83E\uDDEA varDOM: ', val, typeof val, this.type)\n\n        let out // = val\n\n        switch (this.type.toLowerCase()) {\n            case 'all': {\n                out = `Created: ${this.doFormat(this.value.created, 'dt')}, Updated: ${this.doFormat(this.value.modified, 'dt')}`\n                out += `, Size: ${this.doFormat(this.value.size, 'num')}b`\n                break\n            }\n\n            case 'size': { // File size in bytes\n                out = `Size: ${this.doFormat(this.value.size, 'num')}b`\n                break\n            }\n\n            case 'modified':\n            case 'updated': { // updated dates\n                out = `Updated: ${this.doFormat(this.value.modified, 'dt')}`\n                break\n            }\n\n            case 'both': // both created and updated dates\n            case 'created-updated':\n            case 'crup': {\n                out = `Created: ${this.doFormat(this.value.created, 'dt')}, Updated: ${this.doFormat(this.value.modified, 'dt')}`\n                break\n            }\n\n            case 'created':\n            default: {\n                out = `Created: ${this.doFormat(this.value.created, 'dt')}`\n                break\n            }\n        }\n        // if (this.uib) this.shadow.innerHTML = window['uibuilder'].sanitiseHTML(out)\n        // else this.shadow.innerHTML = out\n        this.shadow.innerHTML = out\n\n        // this.shadow.appendChild(this.css)\n    }\n\n    /** Format a value using this.format\n     * @param {Date|string|number} val Value to format\n     * @param {'num'|'dt'} type Type of of input\n     * @returns {*} Formatted value\n     */\n    doFormat(val, type) {\n        if (this.format === '') return val\n\n        // ['d', 'dt', 't', 'k', 'm']\n        let out\n        switch (this.format) {\n            case 'd': {\n                if (type === 'dt') out = (new Date(val)).toLocaleDateString()\n                else out = val\n                break\n            }\n\n            case 't': {\n                if (type === 'dt') out = (new Date(val)).toLocaleTimeString()\n                else out = val\n                break\n            }\n\n            case 'dt': {\n                if (type === 'dt') out = (new Date(val)).toLocaleString()\n                else out = val\n                break\n            }\n\n            case 'k': {\n                if (type === 'num') out = `${uibuilder.round(Number(val) / 1024, 1)} k`\n                else out = val\n                break\n            }\n\n            case 'm': {\n                if (type === 'num') out = `${uibuilder.round(Number(val) / 1048576, 2)} M`\n                else out = val\n                break\n            }\n\n            default: {\n                out = val\n                // break\n            }\n        }\n        return out\n    }\n\n    /** Apply value filter if specified\n     * @param {*} value The value to change\n     * @returns {*} The amended value that will be displayed\n     */\n    // doFilter(value) {\n    //     if (this.filter) {\n    //         // Cater for dotted notation functions (e.g. uibuilder.get)\n    //         const splitFilter = this.filter.split('.')\n    //         let globalFn = globalThis[splitFilter[0]]\n    //         if (globalFn && splitFilter.length > 1) {\n    //             const parts = [splitFilter.pop()]\n    //             parts.forEach( part => {\n    //                 globalFn = globalFn[part]\n    //             } )\n    //         }\n    //         if (!globalFn && this.uib === true) globalFn = globalThis['uibuilder'][splitFilter[0]]\n    //         if (globalFn && typeof globalFn !== 'function' ) globalFn = undefined\n    //         if (globalFn) {\n    //             const argList = value === undefined ? [...this.filterArgs] : [value, ...this.filterArgs]\n    //             value = Reflect.apply(globalFn, value ?? globalFn, argList)\n    //         } else {\n    //             console.warn(`\u26A0\uFE0F [uib-var] Filter function \"${this.filter}\" ${typeof globalFn === 'object' ? 'is an object not a function' : 'not found'}`)\n    //         }\n    //     }\n\n    //     return value\n    // }\n}\n\n// Make the class the default export so it can be used elsewhere\nexport default UibMeta\n\n/** Self register the class to global\n * Enables new data lists to be dynamically added via JS\n * and lets the static methods be called\n */\nwindow['UibMeta'] = UibMeta\n\n// Add the class as a new Custom Element to the window object - Done by uibuilder client library otherwise uibuilder fns can't be used\n// customElements.define('uib-meta', UibMeta)\n", "/** A web component that applies a template to the DOM.\n *\n * Version: See component version\n */\n/*\n  Copyright (c) 2024-2025 Julian Knight (Totally Information)\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n*/\n\nimport TiBaseComponent from './ti-base-component.mjs'\n\n// const template = document.createElement('template')\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`<span></span>`\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`<link type=\"text/css\" rel=\"stylesheet\" href=\"\"../uibuilder/uib-brand.min.css\"\" media=\"all\"><span></span>`\n// template.innerHTML = /** @type {HTMLTemplateElement} */ /*html*/`\n// {/* <style>@import url(\"../uibuilder/uib-brand.min.css\");</style><span></span> */}\n// `\n\n/** Namespace\n * @namespace Live\n */\n\n/**\n * ApplyTemplate is a custom HTML element that allows you to apply a template to the DOM.\n * It listens to changes in specific attributes and updates the DOM accordingly.\n * \n * @class ApplyTemplate\n * @extends TiBaseComponent\n * @description Applies an HTML template to the DOM\n * \n * @element apply-template\n * @memberOf Live\n\n * METHODS FROM BASE:\n * @method config Update runtime configuration, return complete config\n * @method createShadowSelectors Creates the jQuery-like $ and $$ methods\n * @method deepAssign Object deep merger\n * @method doInheritStyles If requested, add link to an external style sheet\n * @method ensureId Adds a unique ID to the tag if no ID defined.\n * @method _connect Call from start of connectedCallback. Sets connected prop and creates shadow selectors\n * @method _event(name,data) Standardised custom event dispatcher\n * @method _disconnect Call from end of disconnectedCallback. Clears connected prop and removes shadow selectors\n * @method _ready Call from end of connectedCallback. Sets connected prop and outputs events\n * @method _uibMsgHandler Not yet in use\n * STANDARD METHODS:\n * @method attributeChangedCallback Called when an attribute is added, removed, updated or replaced\n * @method connectedCallback Called when the element is added to a document\n * @method constructor Construct the component\n * @method disconnectedCallback Called when the element is removed from a document\n\n * OTHER METHODS:\n * None\n\n * @fires apply-template:connected - When an instance of the component is attached to the DOM. `evt.details` contains the details of the element.\n * @fires apply-template:ready - Alias for connected. The instance can handle property & attribute changes\n * @fires apply-template:disconnected - When an instance of the component is removed from the DOM. `evt.details` contains the details of the element.\n * @fires apply-template:attribChanged - When a watched attribute changes. `evt.details.data` contains the details of the change.\n * NOTE that listeners can be attached either to the `document` or to the specific element instance.\n\n * @constructor\n * @throws {Error} Throws an error if the uibuilder client library is not available.\n \n * Standard watched attributes (common across all my components):\n * attr {string|boolean} inherit-style - Optional. Load external styles into component (only useful if using template). If present but empty, will default to './index.css'. Optionally give a URL to load.\n * @attr {string} name - Optional. HTML name attribute. Included in output _meta prop.\n\n * Other watched attributes:\n * @attr {string} template-id - Required. The ID of the template to apply.\n * @attr {string|boolean} once - Optional. If true, the template can only be used once. Default is false.\n\n * PROPS FROM BASE:\n * @prop {number} _iCount Static. The component version string (date updated)\n * @prop {boolean} uib True if UIBUILDER for Node-RED is loaded\n * @prop {object} uibuilder Reference to loaded UIBUILDER for Node-RED client library if loaded (else undefined)\n * @prop {function(string): Element} $ jQuery-like shadow dom selector (or undefined if shadow dom not used)\n * @prop {function(string): NodeList} $$  jQuery-like shadow dom multi-selector (or undefined if shadow dom not used)\n * @prop {boolean} connected False until connectedCallback finishes\n * @prop {string} name Placeholder for the optional name attribute\n * @prop {object} opts This components controllable options - get/set using the `config()` method - empty object by default\n * @prop {string} baseVersion Static. The base component version string (date updated).\n * OTHER STANDARD PROPS:\n * @prop {string} componentVersion Static. The component version string (date updated). Also has a getter that returns component and base version strings.\n\n * Other props:\n * @property {boolean} once - Holder for the once attribute. If true, the template can only be used once. Default is false.\n * @property {string} template-id - The ID of the template to apply.\n * By default, all attributes are also created as properties\n\n * @slot Container contents (only if used template contains a slot)\n\n * See https://github.com/runem/web-component-analyzer?tab=readme-ov-file#-how-to-document-your-components-using-jsdoc\n */\nclass ApplyTemplate extends TiBaseComponent {\n    /** Component version */\n    static componentVersion = '2025-08-28'\n\n    // Holder for once attribute\n    once = false\n\n    /** Makes HTML attribute change watched\n     * @returns {Array<string>} List of all of the html attribs (props) listened to\n     */\n    static get observedAttributes() {\n        return [\n            // Standard watched attributes:\n            /* 'inherit-style', */ 'name',\n            // Other watched attributes:\n            'template-id', 'once',\n        ]\n    }\n\n    /** NB: Attributes not available here - use connectedCallback to reference */\n    constructor() {\n        super()\n        // Only attach the shadow dom if code and style isolation is needed - comment out if shadow dom not required\n        // if (template && template.content) this._construct(template.content.cloneNode(true))\n        // Otherwise, if component styles are needed, use the following instead:\n        // this.prependStylesheet(styles, 0)\n\n        if (!this.uibuilder) throw new Error('[apply-template] uibuilder client library not available')\n    }\n\n    /** Runs when an instance is added to the DOM\n     * Runs AFTER the initial attributeChangedCallback's\n     * @private\n     */\n    connectedCallback() {\n        this._connect() // Keep at start.\n\n        const templateId = this['template-id']\n        const onceOnly = this['once']\n\n        if (!templateId) {\n            throw new Error('[ApplyTemplate] Template id attribute not provided. Template must be identified by an id attribute')\n        }\n\n        const template = document.getElementById(templateId)\n        if (!template || template.tagName !== 'TEMPLATE') {\n            throw new Error(`[ApplyTemplate] Source must be a <template>. id='${templateId}'`)\n        }\n\n        const existContent = this.innerHTML\n        this.innerHTML = '' // Clear any existing content\n\n        let templateContent\n        if (onceOnly === false) {\n            // @ts-ignore\n            templateContent = document.importNode(template.content, true)\n        } else {\n            // NB content.childElementCount = 0 after adoption\n            // @ts-ignore\n            templateContent = document.adoptNode(template.content)\n        }\n\n        this.appendChild(templateContent)\n\n        if (existContent) {\n            const slot = this.getElementsByTagName('slot')\n            if (slot.length > 0) {\n                slot[0].innerHTML = existContent\n            }\n        }\n\n        this._ready() // Keep at end. Let everyone know that a new instance of the component has been connected & is ready\n    }\n\n    /** Runs when an instance is removed from the DOM\n     * @private\n     */\n    disconnectedCallback() {\n        this._disconnect() // Keep at end.\n    }\n\n    /** Runs when an observed attribute changes - Note: values are always strings\n     * NOTE: On initial startup, this is called for each watched attrib set in HTML.\n     *       and BEFORE connectedCallback is called.\n     * @param {string} attrib Name of watched attribute that has changed\n     * @param {string} oldVal The previous attribute value\n     * @param {string} newVal The new attribute value\n     * @private\n     */\n    attributeChangedCallback(attrib, oldVal, newVal) {\n        /** Optionally ignore attrib changes until instance is fully connected\n         * Otherwise this can fire BEFORE everthing is fully connected.\n         */\n        // if (!this.connected) return\n\n        // Don't bother if the new value same as old\n        if ( oldVal === newVal ) return\n        // Create a property from the value - WARN: Be careful with name clashes\n        this[attrib] = newVal\n\n        // Add other dynamic attribute processing here.\n        // If attribute processing doesn't need to be dynamic, process in connectedCallback as that happens earlier in the lifecycle\n\n        // Keep at end. Let everyone know that an attribute has changed for this instance of the component\n        this._event('attribChanged', { attribute: attrib, newVal: newVal, oldVal: oldVal, })\n    }\n}\n\n// Make the class the default export so it can be used elsewhere\nexport default ApplyTemplate\n\n/** Self register the class to global\n * Enables new data lists to be dynamically added via JS\n * and lets the static methods be called\n */\nwindow['ApplyTemplate'] = ApplyTemplate\n\n// Add the class as a new Custom Element to the window object - Done by uibuilder client library otherwise uibuilder fns can't be used\n// customElements.define('apply-template', ApplyTemplate)\n", "/** Define a new zero dependency custom web component ECMA module that can be used as an HTML tag\n *\n * Version: See the class code\n *\n */\n/** Copyright (c) 2025-2025 Julian Knight (Totally Information)\n * https://it.knightnet.org.uk, https://github.com/TotallyInformation\n *\n * Licensed under the Apache License, Version 2.0 (the 'License');\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an 'AS IS' BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport TiBaseComponent from './ti-base-component.mjs'\n\n/** Only use a template if you want to isolate the code and CSS using the Shadow DOM */\nconst template = document.createElement('template')\ntemplate.innerHTML = /* html */`\n    <style>\n        :host {\n            display: block;   /* default is inline */\n            contain: content; /* performance boost */\n            position: fixed;  /* Float over all content */\n            top: var(--uib-control-top, 1.25rem);\n            right: var(--uib-control-right, 1.25rem);\n            z-index: var(--uib-control-z-index, 9999); /* Ensure it floats above other content */\n            max-width: var(--uib-control-max-width, 18.75rem);\n        }\n        \n        .control-container {\n            background: var(--uib-control-bg, hsl(0, 0%, 98%));\n            border: var(--uib-control-border, 1px solid hsl(0, 0%, 85%));\n            border-radius: var(--uib-control-border-radius, 0.5rem);\n            box-shadow: var(--uib-control-shadow, 0 0.25rem 0.75rem hsla(0, 0%, 0%, 0.15));\n            transition: var(--uib-control-transition, all 0.3s ease);\n            position: relative;\n        }\n        \n        .control-container.dragging {\n            transition: none;\n            user-select: none;\n            z-index: 10000;\n        }\n        \n        .emoji-toggle {\n            cursor: pointer;\n            padding: var(--uib-control-emoji-padding, 0.5rem 0.75rem);\n            font-size: var(--uib-control-emoji-size, 1.5rem);\n            background: transparent;\n            border: none;\n            display: block;\n            width: 100%;\n            text-align: center;\n            user-select: none;\n            transition: transform 0.2s ease;\n            position: relative;\n        }\n        \n        .emoji-toggle.dragging {\n            cursor: grabbing;\n        }\n        \n        .emoji-toggle:hover {\n            transform: scale(1.1);\n        }\n        \n        .emoji-toggle:focus {\n            outline: 0.125rem solid var(--uib-control-focus-color, hsl(220, 90%, 50%));\n            outline-offset: 0.125rem;\n        }\n        \n        .content-box {\n            padding: 0;\n            border-top: var(--uib-control-content-border, 1px solid hsl(0, 0%, 90%));\n            background: var(--uib-control-content-bg, hsl(0, 0%, 100%));\n            display: none;\n            min-width: var(--uib-control-content-min-width, 15.625rem);\n        }\n        \n        .content-box.show {\n            display: block;\n            animation: fadeIn 0.2s ease-out;\n        }\n        \n        /* Tab navigation styles */\n        .tab-navigation {\n            display: flex;\n            border-bottom: 1px solid var(--uib-control-content-border, hsl(0, 0%, 90%));\n            background: var(--uib-control-bg, hsl(0, 0%, 98%));\n        }\n        \n        .tab-button {\n            flex: 1;\n            padding: 0.75rem 1rem;\n            border: none;\n            background: transparent;\n            color: var(--uib-control-text-color, hsl(0, 0%, 20%));\n            font-size: var(--uib-control-font-size, 0.9rem);\n            font-weight: 500;\n            cursor: pointer;\n            transition: all 0.2s ease;\n            border-bottom: 2px solid transparent;\n        }\n        \n        .tab-button:hover {\n            background: var(--uib-control-content-bg, hsl(0, 0%, 100%));\n        }\n        \n        .tab-button:focus {\n            outline: 0.125rem solid var(--uib-control-focus-color, hsl(220, 90%, 50%));\n            outline-offset: -0.125rem;\n            z-index: 1;\n            position: relative;\n        }\n        \n        .tab-button.active {\n            background: var(--uib-control-content-bg, hsl(0, 0%, 100%));\n            border-bottom-color: var(--uib-control-focus-color, hsl(220, 90%, 50%));\n            color: var(--uib-control-focus-color, hsl(220, 90%, 50%));\n        }\n        \n        /* Tab content styles */\n        .tab-content {\n            position: relative;\n        }\n        \n        .tab-panel {\n            padding: var(--uib-control-content-padding, 1rem);\n            display: none;\n        }\n        \n        .tab-panel.active {\n            display: block;\n        }\n        \n        .tab-panel:focus {\n            outline: none;\n        }\n        \n        @keyframes fadeIn {\n            from { opacity: 0; transform: translateY(-0.625rem); }\n            to { opacity: 1; transform: translateY(0); }\n        }\n        \n        /* Default content styling */\n        .theme-toggle-section {\n            margin-bottom: 1rem;\n            padding-bottom: 0.75rem;\n            border-bottom: 1px solid var(--uib-control-content-border, hsl(0, 0%, 90%));\n        }\n        \n        .theme-label {\n            display: inline-block;\n            font-size: var(--uib-control-font-size, 0.9rem);\n            font-weight: 500;\n            color: var(--uib-control-text-color, hsl(0, 0%, 20%));\n            margin-right: 0.5rem;\n        }\n        \n        .theme-buttons-container {\n            display: inline-flex;\n            border: 1px solid var(--uib-control-border, hsl(0, 0%, 85%));\n            border-radius: 0.375rem;\n            overflow: hidden;\n            background: var(--uib-control-content-bg, hsl(0, 0%, 100%));\n        }\n        \n        .theme-button {\n            padding: 0.375rem 0.75rem;\n            border: none;\n            background: var(--uib-control-content-bg, hsl(0, 0%, 100%));\n            color: var(--uib-control-text-color, hsl(0, 0%, 20%));\n            font-size: var(--uib-control-font-size, 0.9rem);\n            font-weight: 500;\n            cursor: pointer;\n            transition: all 0.2s ease;\n            border-right: 1px solid var(--uib-control-border, hsl(0, 0%, 85%));\n            min-width: 2.5rem;\n            text-align: center;\n        }\n        \n        .theme-button:last-child {\n            border-right: none;\n        }\n        \n        .theme-button:hover {\n            background: var(--uib-control-bg, hsl(0, 0%, 98%));\n        }\n        \n        .theme-button:focus {\n            outline: 0.125rem solid var(--uib-control-focus-color, hsl(220, 90%, 50%));\n            outline-offset: -0.125rem;\n            z-index: 1;\n            position: relative;\n        }\n        \n        .theme-button.active {\n            background: var(--uib-control-focus-color, hsl(220, 90%, 50%));\n            color: hsl(0, 0%, 100%);\n        }\n        \n        .theme-button.active:hover {\n            background: hsl(220, 90%, 45%);\n        }\n        \n        .content-box p {\n            margin: 0 0 0.5rem 0;\n            color: var(--uib-control-text-color, hsl(0, 0%, 20%));\n            font-size: var(--uib-control-font-size, 0.9rem);\n            line-height: 1.4;\n        }\n        \n        .content-box p:last-child {\n            margin-bottom: 0;\n        }\n    </style>\n    <div class=\"control-container\">\n        <button class=\"emoji-toggle\" type=\"button\" aria-expanded=\"false\" aria-label=\"Toggle control panel (click) or drag to move\">\n            \uD83C\uDF9B\uFE0F\n        </button>\n        <div class=\"content-box\" role=\"region\" aria-label=\"Control panel content\">\n            <div class=\"tab-navigation\" role=\"tablist\" aria-label=\"Content tabs\">\n                <button id=\"tab-btn-1\" class=\"tab-button active\" type=\"button\" role=\"tab\" aria-selected=\"true\" aria-controls=\"tab1\">\n                    Settings\n                </button>\n                <button id=\"tab-btn-2\" class=\"tab-button\" type=\"button\" role=\"tab\" aria-selected=\"false\" aria-controls=\"tab2\">\n                    Page Info\n                </button>\n            </div>\n            <div class=\"tab-content\">\n                <div id=\"tab1\" class=\"tab-panel active\" role=\"tabpanel\" aria-labelledby=\"tab-btn-1\" tabindex=\"0\">\n                    <div class=\"theme-toggle-section\">\n                        <label class=\"theme-label\">Theme:</label>\n                        <div class=\"theme-buttons-container\" role=\"radiogroup\" aria-label=\"Theme selection\">\n                            <button id=\"theme-auto\" class=\"theme-button active\" type=\"button\" data-theme=\"auto\" aria-pressed=\"true\">\n                                Auto\n                            </button>\n                            <button id=\"theme-light\" class=\"theme-button\" type=\"button\" data-theme=\"light\" aria-pressed=\"false\">\n                                Light\n                            </button>\n                            <button id=\"theme-dark\" class=\"theme-button\" type=\"button\" data-theme=\"dark\" aria-pressed=\"false\">\n                                Dark\n                            </button>\n                        </div>\n                    </div>\n                    <slot></slot>\n                </div>\n                <div id=\"tab2\" class=\"tab-panel\" role=\"tabpanel\" aria-labelledby=\"tab-btn-2\" tabindex=\"0\">\n                    <div id=\"viewportSize\">Window Width: -- px, Height: -- px</div>\n                    <div id=\"clientSize\">Client Width: -- px, Height: -- px</div>\n                </div>\n            </div>\n        </div>\n    </div>\n`\n/** Only use this if using Light DOM but want scoped styles */\n// const styles = `\n//     uib-control {\n//         /* Scoped to this component */\n//     }\n// `\n\n/**\n * @class\n * @augments TiBaseComponent\n * @description Define a new zero dependency custom web component that displays as a floating control panel.\n * By default shows just an emoji toggle button that floats over all page content. When clicked,\n * toggles between showing just the emoji and displaying a content box with additional content.\n *\n * @element uib-control\n * @license Apache-2.0\n\n * METHODS FROM BASE: (see TiBaseComponent)\n * STANDARD METHODS:\n  * @function attributeChangedCallback Called when an attribute is added, removed, updated or replaced\n  * @function connectedCallback Called when the element is added to a document\n  * @function constructor Construct the component\n  * @function disconnectedCallback Called when the element is removed from a document\n\n * OTHER METHODS:\n  * @function _setupToggle Private method to setup toggle functionality\n  * @function _setupThemeToggle Private method to setup theme toggle functionality\n  * @function _setupTabs Private method to setup tab functionality\n  * @function _setupDrag Private method to setup drag functionality\n  * @function _savePosition Private method to save position to localStorage\n  * @function _restorePosition Private method to restore position from localStorage\n  * @function _getCurrentTheme Private method to get current theme setting\n  * @function _setTheme Private method to set theme mode\n\n * CUSTOM EVENTS:\n  * \"uib-control:connected\" - When an instance of the component is attached to the DOM. `evt.details` contains the details of the element.\n  * \"uib-control:ready\" - Alias for connected. The instance can handle property & attribute changes\n  * \"uib-control:disconnected\" - When an instance of the component is removed from the DOM. `evt.details` contains the details of the element.\n  * \"uib-control:attribChanged\" - When a watched attribute changes. `evt.details.data` contains the details of the change.\n  * \"uib-control:toggle\" - When the control panel is toggled. `evt.details.data.expanded` indicates whether panel is expanded.\n  * \"uib-control:drag-end\" - When dragging ends. `evt.details.data` contains x and y coordinates.\n  * \"uib-control:position-restored\" - When saved position is restored. `evt.details.data` contains position and timestamp.\n  * \"uib-control:theme-changed\" - When theme is changed. `evt.details.data.theme` contains the selected theme.\n  * \"uib-control:tab-changed\" - When tab is changed. `evt.details.data.activeTab` contains the active tab ID.\n  * NOTE that listeners can be attached either to the `document` or to the specific element instance.\n\n * Standard watched attributes (common across all my components):\n  * @property {string|boolean} inherit-style - Optional. Load external styles into component (only useful if using template). If present but empty, will default to './index.css'. Optionally give a URL to load.\n  * @property {string} name - Optional. HTML name attribute. Included in output _meta prop.\n\n * Other watched attributes:\n  * @property {boolean} close-on-outside-click - Optional. If present, clicking outside the component will close the panel.\n  * @property {string} save-position - Optional. If present, saves the dragged position to localStorage. Value is used as storage key (defaults to 'uib-control-position').\n\n * PROPS FROM BASE: (see TiBaseComponent)\n * OTHER STANDARD PROPS:\n  * @property {string} componentVersion Static. The component version string (date updated). Also has a getter that returns component and base version strings.\n\n * Other props:\n  * By default, all attributes are also created as properties\n\n NB: properties marked with \uD83D\uDCAB are dynamic and have getters/setters.\n\n * CSS Custom Properties (for theming):\n  * --uib-control-top: Top position (default: 1.25rem)\n  * --uib-control-right: Right position (default: 1.25rem)\n  * --uib-control-z-index: Z-index for layering (default: 9999)\n  * --uib-control-max-width: Maximum width of component (default: 18.75rem)\n  * --uib-control-bg: Background color (default: hsl(0, 0%, 98%))\n  * --uib-control-border: Border style (default: 1px solid hsl(0, 0%, 85%))\n  * --uib-control-border-radius: Border radius (default: 0.5rem)\n  * --uib-control-shadow: Box shadow (default: 0 0.25rem 0.75rem hsla(0, 0%, 0%, 0.15))\n  * --uib-control-emoji-size: Size of emoji toggle (default: 1.5rem)\n  * --uib-control-content-padding: Content padding (default: 1rem)\n\n * @slot Container contents - Content displayed in the expandable panel\n\n * @example\n  * <uib-control name=\"myControl\">\n  *   <p>Your control panel content here</p>\n  * </uib-control>\n\n * @example\n  * <uib-control close-on-outside-click save-position=\"my-panel-pos\">\n  *   <div>\n  *     <h3>Draggable Control Panel</h3>\n  *     <button>Action 1</button>\n  *     <button>Action 2</button>\n  *   </div>\n  * </uib-control>\n\n * @example\n  * <!-- Save position with default key -->\n  * <uib-control save-position>\n  *   <p>This panel remembers its position</p>\n  * </uib-control>\n\n * See https://github.com/runem/web-component-analyzer?tab=readme-ov-file#-how-to-document-your-components-using-jsdoc\n */\nclass UibControl extends TiBaseComponent {\n    /** Component version */\n    static componentVersion = '2025-08-28'\n\n    // Unique key for local storage\n    #uniqueKey\n    #toggleButton\n    #dragHandlers = {\n        mouseMove: null,\n        mouseUp: null,\n        touchMove: null,\n        touchEnd: null,\n    }\n    #toggleHandlers = {\n        click: null,\n        keydown: null,\n        outsideClick: null,\n        touchStart: null,\n        touchEnd: null,\n        themeChange: null,\n        tabClick: null,\n        tabKey: null,\n    }\n    #resizeHandler = null\n\n    /** Makes HTML attribute change watched\n     * @returns {Array<string>} List of all of the html attribs (props) listened to\n     */\n    static get observedAttributes() {\n        return [\n            // Standard watched attributes:\n            'inherit-style', 'name',\n            // Other watched attributes:\n            'close-on-outside-click', 'save-position',\n        ]\n    }\n\n    /** NB: Attributes not available here - use connectedCallback to reference */\n    constructor() {\n        super()\n        // Only attach the shadow dom if code and style isolation is needed - comment out if shadow dom not required\n        if (template && template.content) this._construct(template.content.cloneNode(true))\n        // Otherwise, if component styles are needed, use the following instead:\n        // this.prependStylesheet(styles, 0)\n    }\n\n    // #region ---- Internal methods ----\n\n    /** Setup the toggle functionality for the emoji button\n     * @private\n     */\n    _setupToggle() {\n        const toggleButton = this.#toggleButton = this.shadowRoot?.querySelector('.emoji-toggle')\n        const contentBox = this.shadowRoot?.querySelector('.content-box')\n\n        if (!toggleButton || !contentBox) return\n\n        let isExpanded = false\n\n        // Create handler functions for cleanup\n        const clickHandler = () => {\n            isExpanded = !isExpanded\n\n            if (isExpanded) {\n                contentBox.classList.add('show')\n                toggleButton.setAttribute('aria-expanded', 'true')\n            } else {\n                contentBox.classList.remove('show')\n                toggleButton.setAttribute('aria-expanded', 'false')\n            }\n\n            // Dispatch custom event for external listeners\n            this._event('toggle', { expanded: isExpanded, })\n        }\n\n        const keydownHandler = (evt) => {\n            if (evt instanceof KeyboardEvent && evt.key === 'Escape' && isExpanded) {\n                isExpanded = false\n                contentBox.classList.remove('show')\n                toggleButton.setAttribute('aria-expanded', 'false')\n                this._event('toggle', { expanded: false, })\n            }\n        }\n\n        // Add event listeners\n        toggleButton.addEventListener('click', clickHandler)\n        toggleButton.addEventListener('keydown', keydownHandler)\n\n        // For better mobile support, also handle touch events for toggle\n        let touchStartTime = 0\n        let touchStartX = 0\n        let touchStartY = 0\n\n        const touchStartHandler = (evt) => {\n            if (evt.touches.length === 1) {\n                touchStartTime = Date.now()\n                touchStartX = evt.touches[0].clientX\n                touchStartY = evt.touches[0].clientY\n            }\n        }\n\n        const touchEndHandler = (evt) => {\n            if (evt.changedTouches.length === 1) {\n                const touchEndTime = Date.now()\n                const touchEndX = evt.changedTouches[0].clientX\n                const touchEndY = evt.changedTouches[0].clientY\n\n                const duration = touchEndTime - touchStartTime\n                const distance = Math.sqrt(\n                    Math.pow(touchEndX - touchStartX, 2)\n                    + Math.pow(touchEndY - touchStartY, 2)\n                )\n\n                // If it's a quick tap with minimal movement, treat as click\n                if (duration < 300 && distance < 10) {\n                    clickHandler()\n                    evt.preventDefault()\n                }\n            }\n        }\n\n        // Add touch handlers for better mobile click detection\n        toggleButton.addEventListener('touchstart', touchStartHandler, { passive: true, })\n        toggleButton.addEventListener('touchend', touchEndHandler, { passive: false, })\n\n        // Store handlers for cleanup\n        this.#toggleHandlers.click = clickHandler\n        this.#toggleHandlers.keydown = keydownHandler\n        this.#toggleHandlers.touchStart = touchStartHandler\n        this.#toggleHandlers.touchEnd = touchEndHandler\n\n        // Optional: Close when clicking outside (if desired)\n        if (this.hasAttribute('close-on-outside-click')) {\n            const outsideClickHandler = (evt) => {\n                if (isExpanded && evt.target instanceof Node && !this.contains(evt.target)) {\n                    isExpanded = false\n                    contentBox.classList.remove('show')\n                    toggleButton.setAttribute('aria-expanded', 'false')\n                    this._event('toggle', { expanded: false, })\n                }\n            }\n\n            document.addEventListener('click', outsideClickHandler)\n            this.#toggleHandlers.outsideClick = outsideClickHandler\n        }\n\n        // Setup theme toggle functionality\n        this._setupThemeToggle()\n\n        // Setup tab functionality\n        this._setupTabs()\n    }\n\n    /** Setup theme toggle functionality\n     * @private\n     */\n    _setupThemeToggle() {\n        const themeButtonsContainer = this.shadowRoot?.querySelector('.theme-buttons-container')\n        const themeButtons = this.shadowRoot?.querySelectorAll('.theme-button')\n        if (!themeButtonsContainer || !themeButtons?.length) return\n\n        // Get current theme and set initial state\n        const currentTheme = this._getCurrentTheme()\n        this._updateButtonStates(themeButtons, currentTheme)\n\n        // Handle theme button clicks\n        const themeChangeHandler = (evt) => {\n            if (!(evt.target instanceof HTMLButtonElement) || !evt.target.classList.contains('theme-button')) return\n\n            evt.preventDefault()\n\n            const selectedTheme = evt.target.getAttribute('data-theme')\n            if (!selectedTheme) return\n\n            // Update button states and apply theme\n            this._updateButtonStates(themeButtons, selectedTheme)\n            this._setTheme(selectedTheme)\n\n            // Dispatch custom event for external listeners\n            this._event('theme-changed', { theme: selectedTheme, })\n        }\n\n        themeButtonsContainer.addEventListener('click', themeChangeHandler)\n\n        // Store handler for cleanup\n        this.#toggleHandlers.themeChange = themeChangeHandler\n    }\n\n    /** Update the theme button states\n     * @private\n     * @param {NodeList} buttons - The theme button elements\n     * @param {string} activeTheme - The theme to set as active\n     */\n    _updateButtonStates(buttons, activeTheme) {\n        buttons.forEach((button) => {\n            if (!(button instanceof HTMLButtonElement)) return\n\n            const buttonTheme = button.getAttribute('data-theme')\n            const isActive = buttonTheme === activeTheme\n\n            if (isActive) {\n                button.classList.add('active')\n                button.setAttribute('aria-pressed', 'true')\n            } else {\n                button.classList.remove('active')\n                button.setAttribute('aria-pressed', 'false')\n            }\n        })\n    }\n\n    /** Setup tab functionality\n     * @private\n     */\n    _setupTabs() {\n        const tabNavigation = this.shadowRoot?.querySelector('.tab-navigation')\n        const tabButtons = this.shadowRoot?.querySelectorAll('.tab-button')\n        const tabPanels = this.shadowRoot?.querySelectorAll('.tab-panel')\n\n        if (!tabNavigation || !tabButtons?.length || !tabPanels?.length) return\n\n        // Handle tab button clicks\n        const tabClickHandler = (evt) => {\n            if (!(evt.target instanceof HTMLButtonElement) || !evt.target.classList.contains('tab-button')) return\n\n            evt.preventDefault()\n\n            const clickedButton = evt.target\n            const targetPanelId = clickedButton.getAttribute('aria-controls')\n            if (!targetPanelId) return\n\n            // Update button states\n            tabButtons.forEach((button) => {\n                if (!(button instanceof HTMLButtonElement)) return\n\n                const isActive = button === clickedButton\n                if (isActive) {\n                    button.classList.add('active')\n                    button.setAttribute('aria-selected', 'true')\n                } else {\n                    button.classList.remove('active')\n                    button.setAttribute('aria-selected', 'false')\n                }\n            })\n\n            // Update panel visibility\n            tabPanels.forEach((panel) => {\n                if (!(panel instanceof HTMLElement)) return\n\n                const isActive = panel.id === targetPanelId\n                if (isActive) {\n                    panel.classList.add('active')\n                } else {\n                    panel.classList.remove('active')\n                }\n            })\n\n            // Dispatch custom event for external listeners\n            this._event('tab-changed', { activeTab: targetPanelId, })\n        }\n\n        // Handle keyboard navigation\n        const tabKeyHandler = (evt) => {\n            if (!(evt.target instanceof HTMLButtonElement) || !evt.target.classList.contains('tab-button')) return\n\n            const currentIndex = Array.from(tabButtons).indexOf(evt.target)\n            let targetIndex = currentIndex\n\n            switch (evt.key) {\n                case 'ArrowLeft':\n                    targetIndex = currentIndex > 0 ? currentIndex - 1 : tabButtons.length - 1\n                    evt.preventDefault()\n                    break\n                case 'ArrowRight':\n                    targetIndex = currentIndex < tabButtons.length - 1 ? currentIndex + 1 : 0\n                    evt.preventDefault()\n                    break\n                case 'Home':\n                    targetIndex = 0\n                    evt.preventDefault()\n                    break\n                case 'End':\n                    targetIndex = tabButtons.length - 1\n                    evt.preventDefault()\n                    break\n                default:\n                    return\n            }\n\n            const targetButton = tabButtons[targetIndex]\n            if (targetButton instanceof HTMLButtonElement) {\n                targetButton.focus()\n                targetButton.click()\n            }\n        }\n\n        tabNavigation.addEventListener('click', tabClickHandler)\n        tabNavigation.addEventListener('keydown', tabKeyHandler)\n\n        // Store handlers for cleanup\n        this.#toggleHandlers.tabClick = tabClickHandler\n        this.#toggleHandlers.tabKey = tabKeyHandler\n    }\n\n    /** Get the current theme setting\n     * @private\n     * @returns {string} Current theme ('light', 'dark', or 'auto')\n     */\n    _getCurrentTheme() {\n        const htmlElement = document.documentElement\n\n        if (htmlElement.classList.contains('light')) {\n            return 'light'\n        } else if (htmlElement.classList.contains('dark')) {\n            return 'dark'\n        }\n\n        // Check localStorage for saved preference\n        try {\n            const savedTheme = localStorage.getItem('uib-control-theme')\n            if (savedTheme && ['light', 'dark', 'auto'].includes(savedTheme)) {\n                return savedTheme\n            }\n        } catch (error) {\n            console.warn('Failed to read theme preference:', error)\n        }\n\n        return 'auto' // Default to browser preference\n    }\n\n    /** Set the theme mode\n     * @private\n     * @param {string} theme - Theme mode ('light', 'dark', or 'auto')\n     */\n    _setTheme(theme) {\n        const htmlElement = document.documentElement\n\n        // Remove existing theme classes\n        htmlElement.classList.remove('light', 'dark')\n\n        // Apply new theme\n        switch (theme) {\n            case 'light':\n                htmlElement.classList.add('light')\n                break\n            case 'dark':\n                htmlElement.classList.add('dark')\n                break\n            case 'auto':\n                // No class = browser preference\n                break\n            default:\n                console.warn('Invalid theme mode:', theme)\n                return\n        }\n\n        // Save to localStorage\n        try {\n            localStorage.setItem('uib-control-theme', theme)\n        } catch (error) {\n            console.warn('Failed to save theme preference:', error)\n        }\n    }\n\n    /** Setup drag functionality for moving the control panel\n     * @private\n     */\n    _setupDrag() {\n        const toggleButton = this.shadowRoot?.querySelector('.emoji-toggle')\n        const container = this.shadowRoot?.querySelector('.control-container')\n\n        if (!toggleButton || !container) return\n\n        let isDragging = false\n        let dragStarted = false\n        let startX = 0\n        let startY = 0\n        let initialX = 0\n        let initialY = 0\n        const dragThreshold = 5 // pixels to move before drag starts\n\n        // Mouse events\n        const startDrag = (evt) => {\n            const clientX = evt instanceof MouseEvent ? evt.clientX : evt.touches[0].clientX\n            const clientY = evt instanceof MouseEvent ? evt.clientY : evt.touches[0].clientY\n\n            startX = clientX\n            startY = clientY\n\n            const rect = this.getBoundingClientRect()\n            initialX = rect.left\n            initialY = rect.top\n\n            isDragging = true\n            dragStarted = false\n\n            evt.preventDefault()\n        }\n        toggleButton.addEventListener('mousedown', startDrag)\n        const mouseMove = (evt) => {\n            if (!isDragging || !(evt instanceof MouseEvent)) return\n\n            const deltaX = evt.clientX - startX\n            const deltaY = evt.clientY - startY\n\n            // Check if we've moved enough to start dragging\n            if (!dragStarted && (Math.abs(deltaX) > dragThreshold || Math.abs(deltaY) > dragThreshold)) {\n                dragStarted = true\n                container.classList.add('dragging')\n                toggleButton.classList.add('dragging')\n            }\n\n            if (dragStarted) {\n                const newX = initialX + deltaX\n                const newY = initialY + deltaY\n\n                // Constrain to viewport\n                const maxX = window.innerWidth - this.offsetWidth\n                const maxY = window.innerHeight - this.offsetHeight\n\n                const constrainedX = Math.max(0, Math.min(newX, maxX))\n                const constrainedY = Math.max(0, Math.min(newY, maxY))\n\n                this.style.left = `${constrainedX}px`\n                this.style.top = `${constrainedY}px`\n                this.style.right = 'auto'\n                this.style.bottom = 'auto'\n\n                evt.preventDefault()\n            }\n        }\n        const mouseUp = (evt) => {\n            if (!isDragging) return\n\n            const wasDragStarted = dragStarted\n            isDragging = false\n\n            if (dragStarted) {\n                dragStarted = false\n                container.classList.remove('dragging')\n                toggleButton.classList.remove('dragging')\n\n                // Save position if save-position attribute is present\n                if (this.hasAttribute('save-position')) {\n                    this._savePosition()\n                }\n\n                // Dispatch custom event\n                this._event('drag-end', {\n                    x: parseInt(this.style.left, 10) || 0,\n                    y: parseInt(this.style.top, 10) || 0,\n                })\n            }\n\n            // Only prevent click event if we actually dragged\n            if (wasDragStarted) {\n                evt.preventDefault()\n                evt.stopPropagation()\n            }\n        }\n\n        // Touch events for mobile\n        toggleButton.addEventListener('touchstart', startDrag)\n        const touchMove = (evt) => {\n            if (!isDragging || !(evt instanceof TouchEvent) || evt.touches.length !== 1) return\n\n            const touch = evt.touches[0]\n            const deltaX = touch.clientX - startX\n            const deltaY = touch.clientY - startY\n\n            // Check if we've moved enough to start dragging\n            if (!dragStarted && (Math.abs(deltaX) > dragThreshold || Math.abs(deltaY) > dragThreshold)) {\n                dragStarted = true\n                container.classList.add('dragging')\n                toggleButton.classList.add('dragging')\n            }\n\n            if (dragStarted) {\n                const newX = initialX + deltaX\n                const newY = initialY + deltaY\n\n                // Constrain to viewport\n                const maxX = window.innerWidth - this.offsetWidth\n                const maxY = window.innerHeight - this.offsetHeight\n\n                const constrainedX = Math.max(0, Math.min(newX, maxX))\n                const constrainedY = Math.max(0, Math.min(newY, maxY))\n\n                this.style.left = `${constrainedX}px`\n                this.style.top = `${constrainedY}px`\n                this.style.right = 'auto'\n                this.style.bottom = 'auto'\n\n                evt.preventDefault()\n            }\n        }\n        const touchEnd = (evt) => {\n            if (!isDragging) return\n\n            const wasDragStarted = dragStarted\n            isDragging = false\n\n            if (dragStarted) {\n                dragStarted = false\n                container.classList.remove('dragging')\n                toggleButton.classList.remove('dragging')\n\n                // Save position if save-position attribute is present\n                if (this.hasAttribute('save-position')) {\n                    this._savePosition()\n                }\n\n                // Dispatch custom event\n                this._event('drag-end', {\n                    x: parseInt(this.style.left, 10) || 0,\n                    y: parseInt(this.style.top, 10) || 0,\n                })\n            }\n\n            // Only prevent click event if we actually dragged\n            if (wasDragStarted) {\n                evt.preventDefault()\n                evt.stopPropagation()\n            }\n        }\n\n        // Add event listeners and store references for cleanup\n        document.addEventListener('mousemove', mouseMove)\n        document.addEventListener('mouseup', mouseUp)\n        document.addEventListener('touchmove', touchMove)\n        document.addEventListener('touchend', touchEnd)\n        document.addEventListener('touchcancel', touchEnd) // Handle touch cancellation same as touch end\n\n        // Store references for cleanup in disconnectedCallback\n        this.#dragHandlers = {\n            mouseMove,\n            mouseUp,\n            touchMove,\n            touchEnd,\n        }\n    }\n\n    /** Save the current position to localStorage\n     * @private\n     */\n    _savePosition() {\n        const saveKey = this.getAttribute('save-position') || 'uib-control-position'\n        const position = {\n            left: this.style.left,\n            top: this.style.top,\n            timestamp: Date.now(),\n        }\n\n        this.#uniqueKey = this.id ? `${this.id}-${saveKey}` : saveKey\n        try {\n            localStorage.setItem(this.#uniqueKey, JSON.stringify(position))\n        } catch (error) {\n            console.warn('Failed to save uib-control position:', error)\n        }\n    }\n\n    /** Restore saved position from localStorage\n     * @private\n     */\n    _restorePosition() {\n        if (!this.hasAttribute('save-position')) return\n\n        const saveKey = this.getAttribute('save-position') || 'uib-control-position'\n\n        try {\n            const savedData = localStorage.getItem(this.#uniqueKey)\n            if (savedData) {\n                const position = JSON.parse(savedData)\n                if (position.left && position.top) {\n                    this.style.left = position.left\n                    this.style.top = position.top\n                    this.style.right = 'auto'\n                    this.style.bottom = 'auto'\n\n                    // Dispatch event to notify position was restored\n                    this._event('position-restored', {\n                        x: parseInt(position.left, 10) || 0,\n                        y: parseInt(position.top, 10) || 0,\n                        timestamp: position.timestamp,\n                    })\n                }\n            }\n        } catch (error) {\n            console.warn('Failed to restore uib-control position:', error)\n        }\n    }\n\n    /** Function to update the viewport size display\n     * @private\n     */\n    _updateViewportSize() {\n        // const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)\n        // const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)\n\n        const width = window.innerWidth\n        const height = window.innerHeight\n        const viewportEl = this.shadowRoot?.getElementById('viewportSize')\n        if (viewportEl) {\n            viewportEl.textContent = `Window Width: ${width}px, Height: ${height}px`\n        }\n        const clientEl = this.shadowRoot?.getElementById('clientSize')\n        if (clientEl) {\n            clientEl.textContent = `Client Width: ${document.documentElement.clientWidth}px, Height: ${document.documentElement.clientHeight}px`\n        }\n    }\n\n    // #endregion ---- Internal methods ----\n\n    /** Runs when an instance is added to the DOM\n     * Runs AFTER the initial attributeChangedCallback's\n     * @private\n     */\n    connectedCallback() {\n        this._connect() // Keep at start.\n\n        // Add toggle functionality\n        this._setupToggle()\n\n        // Add drag functionality\n        this._setupDrag()\n\n        // Restore saved position if save-position attribute is present\n        this._restorePosition()\n\n        // Initialize theme from saved preference\n        const savedTheme = this._getCurrentTheme()\n        if (savedTheme !== 'auto') {\n            this._setTheme(savedTheme)\n        }\n\n        // Initial call to set the size on page load\n        this._updateViewportSize()\n\n        // Store reference to resize handler for cleanup\n        this.#resizeHandler = this._updateViewportSize.bind(this)\n\n        // Update the size whenever the window is resized\n        window.addEventListener('resize', this.#resizeHandler)\n\n        this._ready() // Keep at end. Let everyone know that a new instance of the component has been connected & is ready\n    }\n\n    /** Runs when an instance is removed from the DOM\n     * @private\n     */\n    disconnectedCallback() {\n        // Remove toggle event handlers\n        if (this.#toggleButton && this.#toggleHandlers) {\n            if (this.#toggleHandlers.click) {\n                this.#toggleButton.removeEventListener('click', this.#toggleHandlers.click)\n            }\n            if (this.#toggleHandlers.keydown) {\n                this.#toggleButton.removeEventListener('keydown', this.#toggleHandlers.keydown)\n            }\n            if (this.#toggleHandlers.touchStart) {\n                this.#toggleButton.removeEventListener('touchstart', this.#toggleHandlers.touchStart)\n            }\n            if (this.#toggleHandlers.touchEnd) {\n                this.#toggleButton.removeEventListener('touchend', this.#toggleHandlers.touchEnd)\n            }\n            if (this.#toggleHandlers.themeChange) {\n                const themeButtonsContainer = this.shadowRoot?.querySelector('.theme-buttons-container')\n                if (themeButtonsContainer) {\n                    themeButtonsContainer.removeEventListener('click', this.#toggleHandlers.themeChange)\n                }\n            }\n            if (this.#toggleHandlers.tabClick || this.#toggleHandlers.tabKey) {\n                const tabNavigation = this.shadowRoot?.querySelector('.tab-navigation')\n                if (tabNavigation) {\n                    if (this.#toggleHandlers.tabClick) {\n                        tabNavigation.removeEventListener('click', this.#toggleHandlers.tabClick)\n                    }\n                    if (this.#toggleHandlers.tabKey) {\n                        tabNavigation.removeEventListener('keydown', this.#toggleHandlers.tabKey)\n                    }\n                }\n            }\n            // Remove outside click handler from document\n            if (this.#toggleHandlers.outsideClick) {\n                document.removeEventListener('click', this.#toggleHandlers.outsideClick)\n            }\n        }\n\n        // Remove resize event listener\n        if (this.#resizeHandler) {\n            window.removeEventListener('resize', this.#resizeHandler)\n            this.#resizeHandler = null\n        }\n\n        // Remove drag event listeners\n        if (this.#dragHandlers.mouseMove) {\n            document.removeEventListener('mousemove', this.#dragHandlers.mouseMove)\n        }\n        if (this.#dragHandlers.mouseUp) {\n            document.removeEventListener('mouseup', this.#dragHandlers.mouseUp)\n        }\n        if (this.#dragHandlers.touchMove) {\n            document.removeEventListener('touchmove', this.#dragHandlers.touchMove)\n        }\n        if (this.#dragHandlers.touchEnd) {\n            document.removeEventListener('touchend', this.#dragHandlers.touchEnd)\n            document.removeEventListener('touchcancel', this.#dragHandlers.touchEnd) // Also remove touchcancel handler\n        }\n\n        // Clear handler references\n        this.#dragHandlers = {\n            mouseMove: null,\n            mouseUp: null,\n            touchMove: null,\n            touchEnd: null,\n        }\n        this.#toggleHandlers = {\n            click: null,\n            keydown: null,\n            outsideClick: null,\n            touchStart: null,\n            touchEnd: null,\n            themeChange: null,\n            tabClick: null,\n            tabKey: null,\n        }\n\n        // Clear element references\n        this.#toggleButton = null\n\n        this._disconnect() // Keep at end.\n    }\n\n    /** Runs when an observed attribute changes - Note: values are always strings\n     * NOTE: On initial startup, this is called for each watched attrib set in HTML.\n     *       and BEFORE connectedCallback is called.\n     * @param {string} attrib Name of watched attribute that has changed\n     * @param {string} oldVal The previous attribute value\n     * @param {string} newVal The new attribute value\n     * @private\n     */\n    attributeChangedCallback(attrib, oldVal, newVal) {\n        /** Optionally ignore attrib changes until instance is fully connected\n         * Otherwise this can fire BEFORE everthing is fully connected.\n         */\n        // if (!this.connected) return\n\n        // Don't bother if the new value same as old\n        if ( oldVal === newVal ) return\n        // Create a property from the value - WARN: Be careful with name clashes\n        this[attrib] = newVal\n\n        // Add other dynamic attribute processing here.\n        // If attribute processing doesn't need to be dynamic, process in connectedCallback as that happens earlier in the lifecycle\n\n        // Keep at end. Let everyone know that an attribute has changed for this instance of the component\n        this._event('attribChanged', { attribute: attrib, newVal: newVal, oldVal: oldVal, })\n    }\n} // ---- end of Class ---- //\n\n// Make the class the default export so it can be used elsewhere\nexport default UibControl\n\n/** Self register the class to global\n * Enables new data lists to be dynamically added via JS\n * and lets the static methods be called\n */\nwindow['UibControl'] = UibControl\n\n// Self-register the HTML tag - Done by uibuilder client library otherwise uibuilder fns can't be used\n// customElements.define('uib-control', UibControl)\n", "/**\n * @kind module\n * @module reactive\n * @description Reactive proxy implementation for uibuilder (Loosely based on Vue.js v3 reactivity)\n * @license Apache-2.0\n * @author Julian Knight (Totally Information)\n * @copyright (c) 2025 Julian Knight (Totally Information)\n */\n\n/**\n * Reactive proxy class that wraps variables/objects to make them reactive\n * @class\n *\n * @example\n * // Basic usage\n * const reactiveData = new Reactive({ count: 0, user: { name: 'John' } })\n * const proxy = reactiveData.create()\n *\n * // Listen to all changes\n * const ref = proxy.onChange((newValue, oldValue, propertyPath, target) => {\n *     console.log(`Property ${propertyPath} changed from ${oldValue} to ${newValue}`)\n * })\n *\n * // Changes will show full paths:\n * proxy.count = 5                // propertyPath = \"count\"\n * proxy.user.name = 'Jane'       // propertyPath = \"user.name\"\n *\n * // Cancel the listener\n * proxy.cancelChange(ref)\n */\nexport class Reactive {\n    static version = '2025-06-14' // Version of the reactive module\n\n    /** Create a new Reactive instance\n     * @param {*} srcvar The source variable to wrap\n     */\n    constructor(srcvar) {\n        // If srcvar is not an object, wrap it in an object to make it proxy-able\n        this.target = typeof srcvar === 'object' && srcvar !== null ? srcvar : { value: srcvar, }\n\n        // Storage for change listeners - watches all changes\n        this.changeListeners = new Map()\n        this.listenerIdCounter = 0\n    }\n\n    /** Helper function to check if an object is already reactive\n     * @param {*} obj Object to check\n     * @returns {boolean} True if the object is already reactive\n     * @private\n     */\n    _isReactive(obj) {\n        return obj && obj.__v_isReactive === true\n    }\n\n    /** Helper function to trigger all change listeners\n     * @param {string} propertyPath Full property path (e.g., \"user.name\")\n     * @param {*} value New value\n     * @param {*} oldValue Previous value\n     * @param {*} target The target object\n     * @private\n     */\n    _triggerListeners(propertyPath, value, oldValue, target) {\n        this.changeListeners.forEach((callback) => {\n            try {\n                callback(value, oldValue, propertyPath, target)\n            } catch (error) {\n                console.warn(`[uibuilder:reactive] Error in onChange listener for \"${propertyPath}\":`, error)\n            }\n        })\n    }\n\n    /** Helper function to make an object reactive with property path tracking\n     * @param {*} obj Object to make reactive\n     * @param {string} basePath Base property path for nested objects\n     * @returns {Proxy} Reactive proxy object\n     * @private\n     */\n    _createReactiveObject(obj, basePath = '') {\n        if (!obj || typeof obj !== 'object') return obj\n        if (this._isReactive(obj)) return obj\n\n        // Don't proxy DOM elements, or other special objects\n        if ( (Element && obj instanceof Element) || obj instanceof Date || obj instanceof RegExp) {\n            console.warn('[uibuilder:reactive] Can not proxy DOM elements or other special objects')\n            return obj\n        }\n\n        const proxy = new Proxy(obj, {\n            get: (target, key, receiver) => {\n                // Mark as reactive\n                if (key === '__v_isReactive') return true\n\n                // Add onChange method to the proxy - simplified to watch all changes\n                if (key === 'onChange') {\n                    return (callback) => {\n                        if (typeof callback !== 'function') {\n                            throw new Error('[uibuilder:reactive] onChange callback must be a function')\n                        }\n\n                        const listenerId = ++this.listenerIdCounter\n                        this.changeListeners.set(listenerId, callback)\n\n                        // Return a reference object that can be used to cancel the listener\n                        return {\n                            id: listenerId,\n                            cancel: () => {\n                                this.changeListeners.delete(listenerId)\n                            },\n                        }\n                    }\n                }\n\n                // Add cancelChange method to the proxy\n                if (key === 'cancelChange') {\n                    return (listenerRef) => {\n                        if (!listenerRef || typeof listenerRef.cancel !== 'function') {\n                            console.warn('[uibuilder:reactive] Invalid listener reference provided to cancelChange')\n                            return false\n                        }\n\n                        try {\n                            listenerRef.cancel()\n                            return true\n                        } catch (error) {\n                            console.warn('[uibuilder:reactive] Error cancelling listener:', error)\n                            return false\n                        }\n                    }\n                }\n\n                const result = Reflect.get(target, key, receiver)\n\n                // If the result is an object, make it reactive too with the extended path\n                if (result && typeof result === 'object' && !this._isReactive(result)) {\n                    const newPath = basePath ? `${basePath}.${String(key)}` : String(key)\n                    return this._createReactiveObject(result, newPath)\n                }\n\n                return result\n            },\n\n            set: (target, key, value, receiver) => {\n                // Don't allow setting the reactive marker or special methods\n                if (key === '__v_isReactive' || key === 'onChange' || key === 'cancelChange') return true\n\n                const oldValue = target[key]\n                const hadKey = Object.prototype.hasOwnProperty.call(target, key)\n                const result = Reflect.set(target, key, value, receiver)\n\n                // Only trigger effects if the value actually changed or it's a new property\n                if (!hadKey || value !== oldValue) {\n                    // Create the full property path\n                    const propertyPath = basePath ? `${basePath}.${String(key)}` : String(key)\n\n                    // Trigger all change listeners with the full property path\n                    this._triggerListeners(propertyPath, value, oldValue, receiver)\n\n                    // Dispatch a custom event for the property change if dispatcher provided\n                    try {\n                        this._dispatchCustomEvent('uibuilder:reactive:propertyChanged', {\n                            property: propertyPath,\n                            value,\n                            oldValue,\n                            target: receiver,\n                        })\n                    } catch (error) {\n                        console.warn('[uibuilder:reactive] Error dispatching custom event:', error)\n                    }\n                }\n\n                return result\n            },\n\n            deleteProperty: (target, key) => {\n                const hadKey = Object.prototype.hasOwnProperty.call(target, key)\n                const oldValue = target[key]\n                const result = Reflect.deleteProperty(target, key)\n\n                if (hadKey && result) {\n                    // Create the full property path\n                    const propertyPath = basePath ? `${basePath}.${String(key)}` : String(key)\n\n                    // Trigger all change listeners for deletion with the full property path\n                    this._triggerListeners(propertyPath, undefined, oldValue, target)\n\n                    // Dispatch a custom event for the property deletion if dispatcher provided\n                    try {\n                        this._dispatchCustomEvent('uibuilder:reactive:propertyDeleted', {\n                            property: propertyPath,\n                            oldValue,\n                            target,\n                        })\n                    } catch (error) {\n                        console.warn('[uibuilder:reactive] Error dispatching delete event:', error)\n                    }\n                }\n\n                return result\n            },\n        })\n\n        return proxy\n    }\n\n    /** Standard fn to create a custom event with details & dispatch it\n     * @param {string} title The event name\n     * @param {*} details Any details to pass to event output\n     * @private\n     */\n    _dispatchCustomEvent(title, details) {\n        const event = new CustomEvent(title, { detail: details, })\n        document.dispatchEvent(event)\n    }\n\n    /** Create and return the reactive proxy\n     * @returns {Proxy} A proxy object that can be used reactively\n     */\n    create() {\n        return this._createReactiveObject(this.target)\n    }\n\n    /** Get the number of active listeners\n     * @returns {number} Number of active change listeners\n     */\n    getListenerCount() {\n        return this.changeListeners.size\n    }\n\n    /** Clear all listeners\n     * @returns {void}\n     */\n    clearAllListeners() {\n        this.changeListeners.clear()\n    }\n}\n\n/** Convenience function to create a reactive proxy (maintains backward compatibility)\n * @param {*} srcvar The source variable to wrap\n * @returns {Proxy} A proxy object that can be used reactively\n */\nexport function reactive(srcvar) {\n    const reactiveInstance = new Reactive(srcvar)\n    return reactiveInstance.create()\n}\n\nexport default Reactive\n", "const FORMATTER_CACHE = new Map()\n\n/** Gets a cached Intl.DateTimeFormat instance.\n * @param {Intl.LocalesArgument} locale Locale code. (e.g. 'en-US')\n * @param {Intl.DateTimeFormatOptions} options Intl options\n * @returns {Intl.DateTimeFormat} A cached Intl.DateTimeFormat instance\n */\nfunction getFormatter(locale, options) {\n    const key = `${locale}|${JSON.stringify(options)}`\n\n    if (!FORMATTER_CACHE.has(key)) {\n        FORMATTER_CACHE.set(\n            key,\n            new Intl.DateTimeFormat(locale, options)\n        )\n    }\n\n    return FORMATTER_CACHE.get(key)\n}\n\n/** Gets the parts of a date for a specific locale.\n * @param {Date} date Input JS Date\n * @param {string} [locale] Locale code. (e.g. 'en-US'). Defaults to browser locale.\n * @returns {Object<string, string>} Object with date parts\n */\nfunction getParts(date, locale = navigator.language) {\n    const formatter = getFormatter(locale, {\n        year: 'numeric',\n        month: '2-digit',\n        day: '2-digit',\n        hour: '2-digit',\n        minute: '2-digit',\n        second: '2-digit',\n        weekday: 'long',\n        hour12: false,\n    })\n\n    return Object.fromEntries(\n        formatter.formatToParts(date).map((/** @type {{ type: any; value: any; }} */ p) => [p.type, p.value])\n    )\n}\n\n/** Gets locale specific names for months and weekdays.\n * @param {Date} date Input JS Date\n * @param {string} [locale] Locale code. (e.g. 'en-US'). Defaults to browser locale.\n * @returns {{ MMMM: string, MMM: string, dddd: string, ddd: string }} Object with month and day names\n */\nfunction getNames(date, locale = navigator.language) {\n    return {\n        MMMM: getFormatter(locale, { month: 'long', }).format(date),\n        MMM: getFormatter(locale, { month: 'short', }).format(date),\n        dddd: getFormatter(locale, { weekday: 'long', }).format(date),\n        ddd: getFormatter(locale, { weekday: 'short', }).format(date),\n    }\n}\n\n/** Format a Date using Intl with optional pattern support.\n * @param {Date|string|number} date Input JS Date, date string, or timestamp\n * @param {string} [pattern] Optional pattern string\n * @param {string} [locale] Locale code. Defaults to browser locale.\n * @returns {string} Formatted date string\n */\nexport function formatDate(date, pattern, locale = navigator.language) {\n    // Attempt to convert to Date if not already\n    if (!(date instanceof Date)) {\n        date = new Date(date)\n    }\n\n    // @ts-ignore\n    if (isNaN(date)) {\n        throw new TypeError('Invalid Date')\n    }\n\n    // Default Intl output if no pattern provided\n    if (pattern == null || pattern === '') {\n        return new Intl.DateTimeFormat(locale).format(date)\n    }\n\n    // Handle ISO shorthand patterns\n    if (pattern === 'iso') {\n        pattern = 'YYYY-MM-DD HH:mm'\n    } else if (pattern === 'ISO') {\n        pattern = 'YYYY-MM-DD HH:mm:ss'\n    }\n\n    const parts = getParts(date, locale)\n    const names = getNames(date, locale)\n\n    const tokens = {\n        YYYY: parts.year,\n        MM: parts.month,\n        DD: parts.day,\n        HH: parts.hour,\n        mm: parts.minute,\n        ss: parts.second,\n        ...names,\n    }\n\n    return pattern.replace(\n        /YYYY|MMMM|MMM|MM|DD|dddd|ddd|HH|mm|ss/g,\n        // @ts-ignore\n        token => tokens[token]\n    )\n}\n\nexport default formatDate\n", "/* eslint-disable no-undef */\n/* eslint-disable jsdoc/valid-types */\n/* eslint-disable jsdoc/check-param-names */\n/* eslint-disable @stylistic/no-multi-spaces */\n// @ts-nocheck\n/** This is the source main file for the uibuilder client library\n * @kind module\n * @module uibuilder\n * @description The client-side Front-End JavaScript for uibuilder in HTML Module form\n *   It provides a number of global objects that can be used in your own javascript.\n *   see the docs folder `./docs/uibuilder.module.md` for details of how to use this fully.\n *\n *   Please use the default index.js file for your own code and leave this as-is.\n *   See Uib._meta for client version string\n * @license Apache-2.0\n * @author Julian Knight (Totally Information)\n * @copyright (c) 2022-2026 Julian Knight (Totally Information)\n */\n\nconst perf = new Map()\nperf.set('loading uibuilder client library', performance.now())\n\n// Fastest way to get the http headers - called in constructor\nconst __uibHeadersPromise = fetch(location.href, { method: 'HEAD', cache: 'no-store', })\n    .then((r) => {\n        // console.log('>> >> HEADERS >> >> ', r.headers)\n        const h = {}\n        r.headers.forEach((v, k) => h[k] = v)\n        window.__uibHeaders = h\n        return h\n        // return r.headers\n    })\n\n// #region --- Type Defs --- //\n/**\n * A string containing HTML markup\n * @typedef {string} html\n */\n/**\n * @type {import('./libs/uib-worker.mjs').UibHeaderWorker} Reference to header worker\n */\n// #endregion --- Type Defs --- //\n\n// We need the Socket.IO & ui libraries & the uib-var component  --- //\n// @ts-ignore - Note: Only works when using esbuild to bundle\nimport Ui from './ui.mjs'\nimport io from 'socket.io-client' // eslint-disable-line import/no-named-as-default\nimport UibVar from '../components/uib-var.mjs'\nimport UibMeta from '../components/uib-meta.mjs'\nimport ApplyTemplate from '../components/apply-template.mjs'\nimport UibControl from '../components/uib-control.mjs'\nimport { reactive as createReactive, Reactive } from './reactive.mjs'\nimport { formatDate } from './libs/format-date-time.mjs'\n// import uibHeaderWorker from './libs/uib-worker.mjs'\n// import { dom } from './tinyDom'\n\n// Incorporate the logger module - NB: This sets a global `log` object for use if it can.\n// import logger from './logger'\n\nconst version = '7.7.0-src'\n\n// #region --- Module-level utility functions --- //\n\n// Detect whether the loaded library is minified or not\nconst isMinified = !(/param/).test(function (param) { })\n\n// TODO - switch to logger module\n// #region --- print/console - debugging output functions --- //\n\n/** Custom logging. e.g. log(2, 'here:there', 'jiminy', {fred:'jim'})()\n * @returns {Function} Log function @example log(2, 'here:there', 'jiminy', {fred:'jim'})()\n */\nfunction log() {\n    // Get the args\n    const args = Array.from(arguments)\n    // 1st arg is the log level/type\n    let level = args.shift()\n    let strLevel\n    switch (level) {\n        case 'trace':\n        case 5: {\n            if (log.level < 5) break\n            level = 5 // make sure level is numeric\n            strLevel = 'trace'\n            break\n        }\n\n        case 'debug':\n        case 4: {\n            if (log.level < 4) break\n            level = 4\n            strLevel = 'debug'\n            break\n        }\n\n        case 'log':\n        case 3: {\n            if (log.level < 3) break\n            level = 3\n            strLevel = 'log'\n            break\n        }\n\n        case 'info':\n        case '':\n        case 2: {\n            if (log.level < 2) break\n            level = 2\n            strLevel = 'info'\n            break\n        }\n\n        case 'warn':\n        case 1: {\n            if (log.level < 1) break\n            level = 1\n            strLevel = 'warn'\n            break\n        }\n\n        case 'error':\n        case 'err':\n        case 0: {\n            if (log.level < 0) break\n            level = 0\n            strLevel = 'error'\n            break\n        }\n\n        case 'print': {\n            if (log.level < 0) break\n            level = 0\n            strLevel = 'print'\n            break\n        }\n\n        default: {\n            level = -1\n            break\n        }\n    }\n\n    // If set to something unknown, no log output\n    if (strLevel === undefined) return function () { }\n\n    // 2nd arg is a heading that will be colour highlighted\n    const head = args.shift()\n\n    // Bind back to console.log (could use console[strLevel] but some levels ignore some formatting, use console.xxx directly or dedicated fn)\n    return Function.prototype.bind.call(\n        console[log.LOG_STYLES[strLevel].console],\n        console,\n        `%c${log.LOG_STYLES[strLevel].pre}${strLevel}%c [${head}]`, `${log.LOG_STYLES.level} ${log.LOG_STYLES[strLevel].css}`, `${log.LOG_STYLES.head} ${log.LOG_STYLES[strLevel].txtCss}`,\n        ...args\n    )\n}\n\n// Nice console styling\nlog.LOG_STYLES = {\n    // 0\n    print: {\n        css: 'background: grey; color: yellow;',\n        txtCss: 'color: grey;',\n        pre: '\u27A1\uFE0F',\n        console: 'log',\n    },\n    error: {\n        css: 'background: red; color: black;',\n        txtCss: 'color: red; ',\n        pre: '\u26D4 ',\n        console: 'error', // or trace\n    },\n    // 1\n    warn: {\n        css: 'background: darkorange; color: black;',\n        txtCss: 'color: darkorange; ',\n        pre: '\u26A0 ',\n        console: 'warn',\n    },\n    // 2\n    info: {\n        css: 'background: aqua; color: black;',\n        txtCss: 'color: aqua;',\n        pre: '\u2757 ',\n        console: 'info',\n    },\n    // 3\n    log: {\n        css: 'background: grey; color: yellow;',\n        txtCss: 'color: grey;',\n        pre: '',\n        console: 'log',\n    },\n    // 4\n    debug: {\n        css: 'background: chartreuse; color: black;',\n        txtCss: 'color: chartreuse;',\n        pre: '',\n        console: 'debug',\n    },\n    // 5\n    trace: {\n        css: 'background: indigo; color: yellow;',\n        txtCss: 'color: hotpink;',\n        pre: '',\n        console: 'log',\n    },\n\n    names: ['print', 'error', 'warn', 'info', 'log', 'debug', 'trace'],\n    reset: 'color: inherit;',\n    head: 'font-weight:bold; font-style:italic;',\n    level: 'font-weight:bold; border-radius: 3px; padding: 2px 5px; display:inline-block;',\n}\n\n/** Default log level - Warn (@since v7.1.0) */\nlog.default = 1\nlet ll\n\n// Check if the script element was found and get the data-log-level attribute (only numeric levels allowed here)\nlet scriptElement\ntry {\n    scriptElement = document.currentScript\n    ll = scriptElement.getAttribute('logLevel')\n} catch (e) {}\n\n// Otherwise check if the import url (for ESM only) has a logLevel query param\nif (ll === undefined) {\n    try {\n        const url = new URL(import.meta.url).searchParams\n        ll = url.get('logLevel')\n    } catch (e) {}\n}\n\n// If either found, check numeric and set default level if so\nif (ll !== undefined) {\n    ll = Number(ll)\n    if (isNaN(ll)) {\n        console.warn( `[Uib:constructor] Cannot set logLevel to \"${scriptElement?.getAttribute('logLevel')}\". Defaults to 0 (error).`)\n        log.default = 0\n    } else log.default = ll\n}\n\n// Set current level to default\nlog.level = log.default\n\n// log.default = isMinified ? 0 : 1  // When using minified lib, assume production and only log errors otherwise also log warn\n\n//#endregion\n\n/** A hack to dynamically load a remote module and wait until it is loaded\n * @param {string} url The URL of the module to load\n * @returns {object|null} Either the result object or null (if the load fails)\n */\n// function loadModule(url) { // eslint-disable-line no-unused-vars\n//     let done\n\n//     import(url)\n//         .then(res => {\n//             log('debug', '>> then >>', res)()\n//             done = res\n//         })\n//         .catch(err => {\n//             console.error(`[uibuilder:loadModule] Could not load module ${url}`, err)\n//             done = null\n//         })\n\n//     //  eslint-disable-next-line no-empty\n//     while (!done) { } // eslint-disable-line no-unmodified-loop-condition\n\n//     return done\n// }\n\n/** Convert JSON to Syntax Highlighted HTML\n * If the `json-viewer` custom element is registered, delegates to its static\n * `renderToHTML` method. Otherwise falls back to the built-in regex renderer.\n * @param {object} json A JSON/JavaScript Object\n * @returns {html} Object reformatted as highlighted HTML\n */\nfunction syntaxHighlight(json) {\n    if (json === undefined) {\n        return '<span class=\"undefined\">undefined</span>'\n    }\n\n    // Use the json-viewer component's pure renderer if it is loaded\n    try {\n        if (JsonViewer) return JsonViewer.renderToHTML(json, { includeStyles: false, })\n    } catch (e) { /* Fall through to built-in renderer on failure */ }\n\n    // Built-in regex-based fallback renderer\n    try {\n        json = JSON.stringify(json, undefined, 4)\n        // json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') // eslint-disable-line newline-per-chained-call\n        json = json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)/g, function (match) {\n            let cls = 'number'\n            if ((/^\"/).test(match)) {\n                if ((/:$/).test(match)) {\n                    cls = 'key'\n                } else {\n                    cls = 'string'\n                }\n            } else if ((/true|false/).test(match)) {\n                cls = 'boolean'\n            } else if ((/null/).test(match)) {\n                cls = 'null'\n            }\n            return `<span class=\"${cls}\">${match}</span>`\n        })\n    } catch (e) {\n        json = `Syntax Highlight ERROR: ${e.message}`\n    }\n    return json\n}\n\n/** msg._ui handling functions */\nconst _ui = new Ui(window, log, syntaxHighlight)\n\n// #endregion --- Module-level utility functions --- //\n\n/** Define and export the Uib class - note that an instance of the class is also exported in the wrap-up\n * @typicalname uibuilder\n */\nexport const Uib = class Uib {\n    // #region --- Static variables ---\n    static _meta = {\n        version: version,\n        type: 'module',\n        displayName: 'uibuilder',\n    }\n    // #endregion ---- ---- ---- ----\n\n    // #region private class vars\n\n    // How many times has the loaded instance connected to Socket.IO (detect if not a new load?)\n    connectedNum = 0\n    // event listener callbacks by property name\n    // #events = {}\n    // Socket.IO channel names\n    _ioChannels = { control: 'uiBuilderControl', client: 'uiBuilderClient', server: 'uiBuilder', }\n    /** setInterval holder for pings @type {function|undefined} */\n    #pingInterval\n    // onChange event callbacks\n    #propChangeCallbacks = {}\n    // onTopic event callbacks\n    #msgRecvdByTopicCallbacks = {}\n    // Is Vue available?\n    isVue = false\n    // What version? Set in startup if Vue is loaded. Won't always work\n    vueVersion = undefined\n    /** setInterval id holder for Socket.IO checkConnect\n     * @type {number|null}\n     */\n    #timerid = null\n    /** True when disconnect() was called intentionally - prevents _onDisconnect from triggering auto-reconnect\n     * @type {boolean}\n     */\n    #manualDisconnect = false\n    // Holds the reference ID for the internal msg change event handler so that it can be cancelled\n    #MsgHandler\n    // Placeholder for io.socket - can't make a # var until # fns allowed in all browsers\n    _socket\n    // Placeholder for an observer that watches the whole DOM for changes - can't make a # var until # fns allowed in all browsers\n    _htmlObserver\n    // Has showMsg been turned on?\n    #isShowMsg = false\n    // Has showStatus been turned on?\n    #isShowStatus = false\n    // If true, URL hash changes send msg back to node-red. Controlled by watchUrlHash()\n    #sendUrlHash = false\n    // Used to help create unique element ID's if one hasn't been provided, increment on use\n    #uniqueElID = 0\n    // Reference to our mini web worker\n    // #headerWorker = uibHeaderWorker\n    // Externally accessible command functions (NB: Case must match) - remember to update _uibCommand for new commands\n    #extCommands = [\n        'elementExists', 'get', 'getManagedVarList', 'getWatchedVars', 'htmlSend', 'include',\n        'navigate', 'scrollTo', 'set', 'showMsg', 'showStatus', 'showOverlay',\n        'uiGet', 'uiWatch', 'watchUrlHash',\n    ]\n\n    /** @type {Object<string, string>} Managed uibuilder variables */\n    #managedVars = {}\n\n    // What status variables to show via showStatus()\n    #showStatus = {\n        online: { var: 'online', label: 'Online?', description: 'Is the browser online?', },\n        ioConnected: { var: 'ioConnected', label: 'Socket.IO connected?', description: 'Is Socket.IO connected?', },\n        connectedNum: { var: 'connectedNum', label: '# reconnections', description: 'How many times has Socket.IO had to reconnect since last page load?', },\n\n        clientId: { var: 'clientId', label: 'Client ID', description: 'Static client unique id set in Node-RED. Only changes when browser is restarted.', },\n        tabId: { var: 'tabId', label: 'Browser tab ID', description: 'Static unique id for the browser\\'s current tab', },\n        cookies: { var: 'cookies', label: 'Cookies', description: 'Cookies set in Node-RED', },\n        httpNodeRoot: { var: 'httpNodeRoot', label: 'httpNodeRoot', description: 'From Node-RED\\' settings.js, affects URL\\'s. May be wrong for pages in sub-folders', },\n        pageName: { var: 'pageName', label: 'Page name', description: 'Actual name of this page', },\n\n        ioNamespace: { var: 'ioNamespace', label: 'SIO namespace', description: 'Socket.IO namespace - unique to each uibuilder node instance', },\n        // ioPath: { 'var': 'ioPath', 'label': 'SIO path', 'description': '', }, // no longer needed in the modern client\n        socketError: { var: 'socketError', label: 'Socket error', description: 'If the Socket.IO connection has failed, says why', },\n\n        msgsSent: { var: 'msgsSent', label: '# msgs sent', description: 'How many standard messages have been sent to Node-RED?', },\n        msgsReceived: { var: 'msgsReceived', label: '# msgs received', description: 'How many standard messages have been received from Node-RED?', },\n        msgsSentCtrl: { var: 'msgsSentCtrl', label: '# control msgs sent', description: 'How many control messages have been sent to Node-RED?', },\n        msgsCtrlReceived: { var: 'msgsCtrlReceived', label: '# control msgs received', description: 'How many control messages have been received from Node-RED?', },\n        originator: { var: 'originator', label: 'Node Originator', description: 'If the last msg from Node-RED was from a `uib-sender` node, this will be its node id so that messasges can be returned to it', },\n        topic: { var: 'topic', label: 'Default topic', description: 'Optional default topic to be included in outgoing standard messages', },\n\n        started: { var: 'started', label: 'Has uibuilder client started?', description: 'Whether `uibuilder.start()` ran successfully. This should self-run and should not need to be run manually', },\n        version: { var: 'version', label: 'uibuilder client version', description: 'The version of the loaded uibuilder client library', },\n        serverTimeOffset: { var: 'serverTimeOffset', label: 'Server time offset (Hrs)', description: 'The number of hours difference between the Node-red server and the client', },\n    }\n\n    // Track ui observers (see uiWatch)\n    #uiObservers = {}\n\n    // CSS selector for querySelectorAll to find elements with known uib attributes.\n    // NOTE: CSS cannot match attribute name prefixes, so this covers known names.\n    //       _uibAttrScanOne handles any uib-prefixed attributes found on matched elements.\n    #uibAttrSel = '[uib-topic], [data-uib-topic], [uib-var], [data-uib-var], [uib-if], [data-uib-if]'\n\n    //#endregion\n\n    // #region public class vars\n\n    // TODO Move to proper getters\n    // #region ---- Externally read-only (via .get method) ---- //\n    // version - moved to _meta\n    // Has the initial Socket.IO connection been made? Used to detect if a page reload or just a disconnect/reconnect\n    initialConnect = null\n    // How many times has the client reconnected to Socket.IO since the page was loaded? Note that this will be 0 on the initial connection, so can be used to detect a page reload vs a disconnect/reconnect\n    reconnected = 0\n    /** Client ID set by uibuilder on connect */\n    clientId = ''\n    /** The collection of cookies provided by uibuilder */\n    cookies = {}\n    /** Copy of last control msg object received from sever */\n    ctrlMsg = {}\n    /** Is Socket.IO client connected to the server? */\n    ioConnected = false\n    // Is the library running from a minified version?\n    isMinified = isMinified\n    // Is the browser tab containing this page visible or not?\n    isVisible = false\n    // Remember the last page (re)load/navigation type: navigate, reload, back_forward, prerender\n    lastNavType = ''\n    // Max msg size that can be sent over Socket.IO - updated by \"client connect\" msg receipt\n    maxHttpBufferSize = 1048576\n    /** Last std msg received from Node-RED */\n    msg = {}\n    /** number of messages sent to server since page load */\n    msgsSent = 0\n    /** number of messages received from server since page load */\n    msgsReceived = 0\n    /** number of control messages sent to server since page load */\n    msgsSentCtrl = 0\n    /** number of control messages received from server since page load */\n    msgsCtrlReceived = 0\n    /** Is the client online or offline? */\n    online = navigator.onLine\n    /** last control msg object sent via uibuilder.send() @since v2.0.0-dev3 */\n    sentCtrlMsg = {}\n    /** last std msg object sent via uibuilder.send() */\n    sentMsg = {}\n    /** placeholder to track time offset from server, see fn socket.on(ioChannels.server ...) */\n    serverTimeOffset = null\n    /** placeholder for a socket error message */\n    socketError = null\n    // tab identifier from session storage\n    tabId = ''\n    // Actual name of current page (set in constructor)\n    pageName = null\n    // Is the DOMPurify library loaded? Updated in start()\n    purify = false\n    // Is the Markdown-IT library loaded? Updated in start()\n    markdown = false\n    // Current URL hash. Initial set is done from start->watchHashChanges via a set to make it watched\n    urlHash = location.hash\n    // HTTP Headers on initial load - contain useful uibuilder info\n    httpHeaders = {}\n    // #endregion ---- ---- ---- ---- //\n\n    // TODO Move to proper getters/setters\n    // #region ---- Externally Writable (via .set method, read via .get method) ---- //\n    /** Default originator node id - empty string by default\n     * @type {string}\n     */\n    originator = ''\n    /** Default topic - used by send if set and no topic provided\n     * @type {(string|undefined)}\n     */\n    topic = undefined\n    /** Either undefined or a reference to a uib router instance\n     * Set by uibrouter, do not set manually.\n     */\n    uibrouterinstance\n    /** Set by uibrouter, do not set manually */\n    uibrouter_CurrentRoute\n    // #endregion ---- ---- ---- ---- //\n\n    // #region ---- These are unlikely to be needed externally: ----\n    autoSendReady = true\n    httpNodeRoot = '' // Node-RED setting (via cookie)\n    ioNamespace = ''\n    ioPath = ''\n    retryFactor = 1.5       // starting delay factor for subsequent reconnect attempts\n    retryMs = 2000          // starting retry ms period for manual socket reconnections workaround\n    storePrefix = 'uib_'    // Prefix for all uib-related localStorage\n    started = false\n    // NOTE: These can only change when a client (re)connects\n    socketOptions = {\n        path: this.ioPath,\n        // https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API\n        // https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API\n        // https://socket.io/get-started/webtransport\n        // NOTE: webtransport requires HTTP/3 and TLS. HTTP/2 & 3 not yet available in Node.js\n        // transports: ['polling', 'websocket', 'webtransport'],\n        transports: ['polling', 'websocket'],\n        // Using callback so that they are updated automatically on (re)connect\n        // Only put things in here that will be valid for a websocket connected session\n        auth: (cb) => {\n            cb({\n                clientVersion: version,\n                clientId: this.clientId,\n                pathName: window.location.pathname,\n                urlParams: Object.fromEntries(new URLSearchParams(location.search)),\n                pageName: this.pageName,\n                tabId: this.tabId,\n                lastNavType: this.lastNavType,\n                connectedNum: ++this.connectedNum,\n                // Used to calculate the diff between the server and client connection timestamps - reported if >1 minute\n                browserConnectTimestamp: (new Date()).toISOString(),\n            })\n        },\n        transportOptions: {\n            // Can only set headers when polling\n            polling: {\n                extraHeaders: {\n                    'x-clientid': `${Uib._meta.displayName}; ${Uib._meta.type}; ${Uib._meta.version}; ${this.clientId}`,\n                },\n            },\n        },\n    }\n    // #endregion -- not external --\n\n    // #endregion --- End of variables ---\n\n    // #region ------- Getters and Setters ------- //\n\n    // Change logging level dynamically (affects both console. and print.)\n    set logLevel(level) {\n        log.level = level\n        console.log(\n            '%c\u2757 info%c [logLevel]',\n            `${log.LOG_STYLES.level} ${log.LOG_STYLES.info.css}`,\n            `${log.LOG_STYLES.head} ${log.LOG_STYLES.info.txtCss}`,\n            `Set to ${level} (${log.LOG_STYLES.names[level]})`\n        ) /* changeLogLevel(level)*/\n    }\n    get logLevel() { return log.level }\n\n    get meta() { return Uib._meta }\n\n    /** Extract the root property from a nested property path (e.g., 'myvar.aprop' or 'myvar[\"bprop\"]').\n     * @private\n     * @param {string} prop The property name or nested property path\n     * @returns {Object<boolean, string, string|null>} Whether the prop is a nested path,\n     *   the root property name (e.g., 'myvar' from 'myvar.aprop' or 'myvar[\"bprop\"]'),\n     *   and the nested path or null if not a nested path\n     */\n    _nestedPath(prop) {\n        const isNestedPath = prop.includes('.') || prop.includes('[')\n        let nestedPath = null\n        let rootProp\n        if (isNestedPath) {\n            const dotIdx = prop.indexOf('.')\n            const bracketIdx = prop.indexOf('[')\n            let sepIdx = -1\n            if (dotIdx >= 0 && bracketIdx >= 0) sepIdx = Math.min(dotIdx, bracketIdx)\n            else if (dotIdx >= 0) sepIdx = dotIdx\n            else if (bracketIdx >= 0) sepIdx = bracketIdx\n            if (sepIdx > 0) {\n                // Extract the root property and nested path\n                rootProp = prop.substring(0, sepIdx)\n                // For bracket notation, keep the '[' so _setNestedPath can properly strip quotes\n                nestedPath = prop.substring(prop[sepIdx] === '[' ? sepIdx : sepIdx + 1)\n            }\n        }\n        return { isNestedPath, rootProp, nestedPath, }\n    }\n\n    /** Function to set uibuilder properties to a new value - works on any property except _* or #*\n     * Also triggers any event listeners.\n     * Supports nested property paths (e.g., 'myvar.aprop' or 'myvar[\"bprop\"]').\n     * Example: this.set('msg', {topic:'uibuilder', payload:42});\n     * Example: this.set('myvar.nested.prop', 42);\n     * @param {string} prop Any uibuilder property who's name does not start with a _ or #\n     * @param {*} val The set value of the property or a string declaring that a protected property cannot be changed\n     * @param {boolean} [store] If true, the variable is also saved to the browser localStorage if possible\n     * @param {boolean} [autoload] If true & store is true, on load, uib will try to restore the value from the store automatically\n     * @returns {*} Input value\n     */\n    set(prop, val, store = false, autoload = false) {\n        // Check for excluded properties - we don't want people to set these\n        // if (this.#excludedSet.indexOf(prop) !== -1) {\n        if (prop.startsWith('_') || prop.startsWith('#')) {\n            log('warn', 'Uib:set', `Cannot use set() on protected property \"${prop}\"`)()\n            return `Cannot use set() on protected property \"${prop}\"`\n        }\n\n        // Check if this is a nested property path (contains . or [)\n        const { isNestedPath, rootProp, nestedPath, } = this._nestedPath(prop)\n        // console.log('\uD83E\uDEB2 is nested?', { prop, isNestedPath, rootProp, nestedPath, })\n\n        // Check for an old value\n        const oldVal = isNestedPath\n            ? this._resolveNestedPath(this, prop)\n            : (this[prop] ?? undefined)\n\n        if (isNestedPath && nestedPath) {\n            // Ensure root property exists and is an object\n            if (this[rootProp] == null || typeof this[rootProp] !== 'object') {\n                this[rootProp] = {}\n            }\n            // Set the nested property\n            this._setNestedPath(this[rootProp], nestedPath, val)\n            // Keep track of all managed variables (track root property for nested paths)\n            this.#managedVars[rootProp] = rootProp\n        } else {\n            // We must add the var to the uibuilder object\n            this[prop] = val\n            // Keep track of all managed variables (track root property for nested paths)\n            this.#managedVars[prop] = prop\n        }\n\n        // If requested, save to store (save the entire root object for nested paths)\n        if (store === true) this.setStore(rootProp, isNestedPath ? this[rootProp] : val, autoload)\n\n        log('trace', 'Uib:set', `prop set - prop: ${prop}, val: `, val, ` store: ${store}, autoload: ${autoload}`)()\n\n        // Trigger this prop's event callbacks (listeners which are set by this.onChange)\n        // Fire event for the root property (since that's what actually changed)\n        const eventProp = isNestedPath ? rootProp : prop\n        const eventVal = this[eventProp] // get the current value of the root property (which will include the nested changes if it's a nested path)\n\n        // trigger an event on the prop name, pass both the name and value to the event details\n        this._dispatchCustomEvent('uibuilder:propertyChanged', { prop: eventProp, value: eventVal, oldValue: oldVal, store: store, autoload: autoload, })\n        this._dispatchCustomEvent(`uibuilder:propertyChanged:${eventProp}`, { prop: eventProp, value: eventVal, oldValue: oldVal, store: store, autoload: autoload, })\n\n        // And return the (root) value for good measure\n        return eventVal\n    }\n\n    /** Function to get the value of a uibuilder property\n     * Supports nested property paths (e.g., 'myvar.aprop' or 'myvar[\"bprop\"]').\n     * Example: uibuilder.get('msg')\n     * Example: uibuilder.get('myvar.nested.prop')\n     * @param {string} prop The name of the property to get as long as it does not start with a _ or #\n     * @returns {*|undefined} The current value of the property\n     */\n    get(prop) {\n        // Handle special properties first - these are either protected or virtual properties that don't exist directly on the uibuilder object\n        if (prop.startsWith('_') || prop.startsWith('#')) {\n            log('warn', 'Uib:get', `Cannot use get() on protected property \"${prop}\"`)()\n            return\n        }\n        if (prop === 'version') return Uib._meta.version\n        if (prop === 'msgsCtrl') return this.msgsCtrlReceived\n        if (prop === 'reconnections') return this.connectedNum\n\n        // Extract root property for nested paths\n        const { isNestedPath, rootProp, } = this._nestedPath(prop)\n\n        // Handle nested paths\n        if (isNestedPath) {\n            const value = this._resolveNestedPath(this, prop)\n            if (value === undefined) {\n                log('info', 'Uib:get', `get() - property \"${prop}\" is undefined`)()\n            }\n            return value\n        }\n\n        if (this[prop] === undefined) {\n            log('info', 'Uib:get', `get() - property \"${prop}\" is undefined`)()\n        }\n        return this[prop]\n    }\n\n    /** Write to localStorage if possible. console error output if can't write\n     * Also uses this.storePrefix\n     * @example\n     *   uibuilder.setStore('fred', 42)\n     *   console.log(uibuilder.getStore('fred'))\n     * @param {string} id localStorage var name to be used (prefixed with 'uib_')\n     * @param {*} value value to write to localstore\n     * @param {boolean} [autoload] If true, on load, uib will try to restore the value from the store\n     * @returns {boolean} True if succeeded else false\n     */\n    setStore(id, value, autoload = false) {\n        let autoVars = {}\n        if (autoload === true) {\n            try {\n                autoVars = this.getStore('_uibAutoloadVars') || {}\n            } catch (e) {}\n        }\n        if (typeof value === 'object') {\n            try {\n                value = JSON.stringify(value)\n            } catch (e) {\n                log('error', 'Uib:setStore', 'Cannot stringify object, not storing. ', e)()\n                return false\n            }\n        }\n        try {\n            localStorage.setItem(this.storePrefix + id, value)\n            if (autoload) {\n                autoVars[id] = id\n                try {\n                    localStorage.setItem(this.storePrefix + '_uibAutoloadVars', JSON.stringify(autoVars))\n                } catch (e) {\n                    log('error', 'Uib:setStore', 'Cannot save autoload list. ', e)()\n                }\n            }\n            this._dispatchCustomEvent('uibuilder:propertyStored', { prop: id, value: value, autoload: autoload, })\n            return true\n        } catch (e) {\n            log('error', 'Uib:setStore', 'Cannot write to localStorage. ', e)()\n            return false\n        }\n    } // --- end of setStore --- //\n\n    /** Attempt to get and re-hydrate a key value from localStorage\n     * Note that all uib storage is automatically prefixed using this.storePrefix\n     * @param {*} id The key of the value to attempt to retrieve\n     * @returns {*|null|undefined} The re-hydrated value of the key or null if key not found, undefined on error\n     */\n    getStore(id) {\n        try {\n            // @ts-ignore\n            return JSON.parse(localStorage.getItem(this.storePrefix + id))\n        } catch (e) { }\n        try {\n            return localStorage.getItem(this.storePrefix + id)\n        } catch (e) {\n            return undefined\n        }\n    }\n\n    /** Remove a given id from the uib keys in localStorage\n     * @param {*} id The key to remove\n     */\n    removeStore(id) {\n        try {\n            localStorage.removeItem(this.storePrefix + id)\n        } catch (e) { }\n    }\n\n    /** Returns a list of the externally accessible command functions that are available to be called from Node-RED\n     * @returns {string[]} List of externally accessible command functions\n     */\n    getCommandList() {\n        return this.#extCommands\n    }\n\n    /** Returns a list of uibuilder properties (variables) that can be watched with onChange\n     * @returns {Object<string,string>} List of uibuilder managed variables\n     */\n    getManagedVarList() {\n        return this.#managedVars\n    }\n\n    getWatchedVars() {\n        return Object.keys(this.#propChangeCallbacks)\n    }\n\n    // #endregion ------- -------- ------- //\n\n    // #region ------- Our own event handling system ---------- //\n\n    /** Standard fn to create a custom event with details & dispatch it\n     * @param {string} title The event name\n     * @param {*} details Any details to pass to event output\n     * @private\n     */\n    _dispatchCustomEvent(title, details) {\n        const event = new CustomEvent(title, { detail: details, })\n        document.dispatchEvent(event)\n    }\n\n    // See the this.#propChangeCallbacks & msgRecvdByTopicCallbacks private vars\n\n    /** Register on-change event listeners for uibuilder tracked properties\n     * Make it possible to register a function that will be run when the property changes.\n     * Note that you can create listeners for non-existant properties\n     * @example uibuilder.onChange('msg', (msg) => { console.log('uibuilder.msg changed! It is now: ', msg) })\n     *\n     * @param {string} prop The property of uibuilder that we want to monitor\n     * @param {Function} callback The function that will run when the property changes, parameter is the new value of the property after change\n     * @returns {number} A reference to the callback to cancel, save and pass to uibuilder.cancelChange if you need to remove a listener\n     */\n    onChange(prop, callback) {\n        // Note: Property does not have to exist yet\n\n        // console.debug(`[Uib:onchange] pushing new callback (event listener) for property: ${prop}`)\n\n        // Create a new array or add to the array of callback functions for the property in the events object\n        // if (this.#events[prop]) {\n        //     this.#events[prop].push(callback)\n        // } else {\n        //     this.#events[prop] = [callback]\n        // }\n\n        // Make sure we have an object to receive the saved callback, update the latest reference number\n        if (!this.#propChangeCallbacks[prop]) this.#propChangeCallbacks[prop] = { _nextRef: 1, }\n        else this.#propChangeCallbacks[prop]._nextRef++\n\n        const nextCbRef = this.#propChangeCallbacks[prop]._nextRef\n\n        // Register the callback function. It is saved so that we can remove the event listener if we need to\n        const propChangeCallback = this.#propChangeCallbacks[prop][nextCbRef] = function propChangeCallback(e) {\n            // If the prop name matches the 1st arg in the onChange fn:\n            if (prop === e.detail.prop) {\n                const value = e.detail.value\n                // console.warn('[Uib:onChange:evt] uibuilder:propertyChanged. ', e.detail)\n                // Set the callback fn's `this` and its single argument to the msg\n                callback.call(value, value)\n            }\n        }\n\n        document.addEventListener('uibuilder:propertyChanged', propChangeCallback)\n\n        return nextCbRef\n    } // ---- End of onChange() ---- //\n\n    cancelChange(prop, cbRef) {\n        document.removeEventListener('uibuilder:propertyChanged', this.#propChangeCallbacks[prop][cbRef])\n        delete this.#propChangeCallbacks[prop][cbRef]\n        // this.#propChangeCallbacks[topic]._nextRef-- // Don't bother, let the ref# increase\n    }\n\n    /** Register a change callback for a specific msg.topic (works for std and ctrl msgs)\n     * Similar to onChange but more convenient if needing to differentiate by msg.topic.\n     * @example let otRef = uibuilder.onTopic('mytopic', function(){ console.log('Received a msg with msg.topic=`mytopic`. msg: ', this) })\n     * To cancel a change listener: uibuilder.cancelTopic('mytopic', otRef)\n     * Since v7.6, added ctrl msgs so that <uib-var> and uib-topic in HTML can process control as well as standard msgs\n     *\n     * @param {string} topic The msg.topic we want to listen for\n     * @param {Function} callback The function that will run when an appropriate msg is received. `this` inside the callback as well as the cb's single argument is the received msg.\n     * @returns {number} A reference to the callback to cancel, save and pass to uibuilder.cancelTopic if you need to remove a listener\n     */\n    onTopic(topic, callback) {\n        // Make sure we have an object to receive the saved callback, update the latest reference number\n        if (!this.#msgRecvdByTopicCallbacks[topic]) this.#msgRecvdByTopicCallbacks[topic] = { _nextRef: 1, }\n        else this.#msgRecvdByTopicCallbacks[topic]._nextRef++\n\n        const nextCbRef = this.#msgRecvdByTopicCallbacks[topic]._nextRef\n\n        // Register the callback function. It is saved so that we can remove the event listener if we need to\n        const msgRecvdEvtCallback = this.#msgRecvdByTopicCallbacks[topic][nextCbRef] = function msgRecvdEvtCallback(e) {\n            const msg = e.detail\n            // console.log('[Uib:onTopic:evt] uibuilder:stdMsgReceived where topic matches. ', e.detail)\n            if (msg.topic === topic) {\n                // Set the callback fn's `this` and its single argument to the msg\n                callback.call(msg, msg)\n            }\n        }\n\n        document.addEventListener('uibuilder:stdMsgReceived', msgRecvdEvtCallback)\n        document.addEventListener('uibuilder:ctrlMsgReceived', msgRecvdEvtCallback)\n\n        return nextCbRef\n    }\n\n    cancelTopic(topic, cbRef) {\n        document.removeEventListener('uibuilder:stdMsgReceived', this.#msgRecvdByTopicCallbacks[topic][cbRef])\n        document.removeEventListener('uibuilder:ctrlMsgReceived', this.#msgRecvdByTopicCallbacks[topic][cbRef])\n        // this.#msgRecvdCallbacks[topic]._nextRef-- // Don't bother, let the ref# increase\n    }\n\n    /** Trigger event listener for a given property\n     * Called when uibuilder.set is used\n     *\n     * @param {*} prop The property for which to run the callback functions\n     * arguments: Additional arguments contain the value to pass to the event callback (e.g. newValue)\n     */\n    // emit(prop) {\n    //     var evt = this.#events[prop]\n    //     if (!evt) {\n    //         return\n    //     }\n    //     var args = Array.prototype.slice.call(arguments, 1)\n    //     for (var i = 0; i < evt.length; i++) {\n    //         evt[i].apply(this, args)\n    //     }\n    //     log('trace', 'Uib:emit', `${evt.length} listeners run for prop ${prop} `)()\n    // }\n\n    /** Forcibly removes all event listeners from the events array\n     * Use if you need to re-initialise the environment\n     */\n    // clearEventListeners() {\n    //     this.#events = []\n    // } // ---- End of clearEventListeners() ---- //\n\n    /** Clear a single property event listeners\n     * @param {string} prop The property of uibuilder for which we want to clear the event listener\n     */\n    // clearListener(prop) {\n    //     if (this.#events[prop]) delete this.#events[prop]\n    // }\n\n    // #endregion ---------- End of event handling system ---------- //\n\n    // #region ------- General Utility Functions -------- //\n\n    /** Check supplied msg from server for a timestamp - if received, work out & store difference to browser time\n     * @param {object} receivedMsg A message object recieved from Node-RED\n     * @returns {void} Updates self.serverTimeOffset if different to previous value\n     * @private\n     */\n    _checkTimestamp(receivedMsg) {\n        if (Object.prototype.hasOwnProperty.call(receivedMsg, 'serverTimestamp')) {\n            const serverTimestamp = new Date(receivedMsg.serverTimestamp)\n            // @ts-ignore\n            const offset = Math.round(((new Date()) - serverTimestamp) / 3600000) // in ms /3.6m to get hours\n            if (offset !== this.serverTimeOffset) {\n                log('trace', `Uib:checkTimestamp:${this._ioChannels.server} (server)`, `Offset changed to: ${offset} from: ${this.serverTimeOffset}`)()\n                this.set('serverTimeOffset', offset)\n            }\n        }\n    }\n\n    /** Set up an event listener to watch for hash changes\n     * and set the watchable urlHash variable\n     * @private\n     */\n    _watchHashChanges() {\n        this.set('urlHash', location.hash)\n        window.addEventListener('hashchange', (event) => {\n            this.set('urlHash', location.hash)\n            if (this.#sendUrlHash === true) {\n                this.send({ topic: 'hashChange', payload: location.hash, newHash: this.keepHashFromUrl(event.newURL), oldHash: this.keepHashFromUrl(event.oldURL), })\n            }\n        })\n    }\n\n    /** Returns a new array containing the intersection of the 2 input arrays\n     * @param {Array} a1 Array to check\n     * @param {Array} a2 Array to intersect\n     * @returns {Array} The intersection of the 2 arrays (may be an empty array)\n     */\n    arrayIntersect(a1, a2) {\n        return a1.filter(uName => a2.includes(uName))\n    }\n\n    /** Copies a uibuilder variable to the browser clipboard\n     * @param {string} varToCopy The name of the uibuilder variable to copy to the clipboard\n     */\n    copyToClipboard(varToCopy) {\n        let data = ''\n        try {\n            data = JSON.stringify(this.get(varToCopy))\n        } catch (e) {\n            log('error', 'copyToClipboard', `Could not copy \"${varToCopy}\" to clipboard.`, e.message)()\n        }\n        navigator.clipboard.writeText(data)\n    } // --- End of copyToClipboard --- //\n\n    /** Does the chosen CSS Selector currently exist?\n     * Automatically sends a msg back to Node-RED unless turned off.\n     * @param {string} cssSelector Required. CSS Selector to examine for visibility\n     * @param {boolean} [msg] Optional, default=true. If true also sends a message back to Node-RED\n     * @returns {boolean} True if the element exists\n     */\n    elementExists(cssSelector, msg = true) {\n        const el = document.querySelector(cssSelector)\n\n        let exists = false\n        if (el !== null) exists = true\n\n        if (msg === true) {\n            this.send({\n                payload: exists,\n                info: `Element \"${cssSelector}\" ${exists ? 'exists' : 'does not exist'}`,\n            })\n        }\n\n        return exists\n    } // --- End of elementExists --- //\n\n    /** Format a Date using Intl with optional pattern support.\n     * @param {Date|string|number} date Input JS Date, date string, or timestamp\n     * @param {string} [pattern] Optional pattern string\n     * @param {string} [locale] Locale code. Defaults to browser locale.\n     * @returns {string} Formatted date string\n     */\n    // formatDate = formatDate\n    formatDate = formatDate\n\n    /** Format a number using the INTL standard library - compatible with uib-var filter function\n     * @param {number} value Number to format\n     * @param {number} decimalPlaces Number of decimal places to include. Default=no default\n     * @param {string} intl standard locale spec, e.g. \"ja-JP\" or \"en-GB\". Default=navigator.language\n     * @param {object} opts INTL library options object. Optional\n     * @returns {string} formatted number\n     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString\n     */\n    formatNumber(value, decimalPlaces, intl, opts) {\n        if (isNaN(value)) {\n            log('error', 'formatNumber', `Value must be a number. Value type: \"${typeof value}\"`)()\n            return 'NaN'\n        }\n        if (!opts) opts = {}\n        if (!intl) intl = navigator.language ? navigator.language : 'en-GB'\n        if (typeof decimalPlaces === 'number') {\n            opts.minimumFractionDigits = decimalPlaces\n            opts.maximumFractionDigits = decimalPlaces\n        }\n        let out\n        try {\n            out = Number(value).toLocaleString(intl, opts)\n        } catch (e) {\n            log('error', 'formatNumber', `${e.message}. value=${value}, dp=${decimalPlaces}, intl=\"${intl}\", opts=${JSON.stringify(opts)}`)()\n            return 'NaN'\n        }\n        return out\n    }\n\n    /** Attempt to get rough size of an object\n     * @param {*} obj Any serialisable object\n     * @returns {number|undefined} Rough size of object in bytes or undefined\n     */\n    getObjectSize(obj) {\n        let size\n        try {\n            const jsonString = JSON.stringify(obj)\n            // Encode the string to a Uint8Array and measure its length\n            const encoder = new TextEncoder()\n            const uint8Array = encoder.encode(jsonString)\n            size = uint8Array.length\n        } catch (e) {\n            log('error', 'uibuilder:getObjectSize', 'Could not stringify, cannot determine size', obj, e)()\n        }\n        return size\n    }\n\n    /** Returns true if a uibrouter instance is loaded, otherwise returns false\n     * @returns {boolean} true if uibrouter instance loaded else false\n     */\n    hasUibRouter() {\n        return !!this.uibrouterinstance\n    }\n\n    /** Check if an attribute name is a uibuilder-specific attribute.\n     * Matches names starting with 'uib-', 'data-uib-', or ':'.\n     * @param {string} name The attribute name to check\n     * @returns {boolean} True if the attribute name is a uib attribute\n     */\n    isUibAttribute(name) {\n        return name.startsWith('uib-') || name.startsWith('data-uib-') || name.startsWith(':')\n    }\n\n    /** Only keep the URL Hash & ignoring query params\n     * @param {string} url URL to extract the hash from\n     * @returns {string} Just the route id\n     */\n    keepHashFromUrl(url) {\n        if (!url) return ''\n        return '#' + url.replace(/^.*#(.*)/, '$1').replace(/\\?.*$/, '')\n    }\n\n    /** Standardised logging function that uses the log level system and can be extended in the future to do more than just log to the console\n     * @param {...*} arguments The arguments to log,\n     *   first argument can optionally be a log level string or number (e.g., 'info', 'warn', 'error', 'debug', 'trace')\n     *   2nd argument can optionally be a source string to identify the source of the log (e.g., 'uibuilder:myFunction')\n     *   Remaining arguments are the data to log, can be multiple and of any type.\n     */\n    log() {\n        log(...arguments)()\n    }\n\n    /** Output the current call stack to the console */\n    logStack() {\n        const stack = this.stack()\n        stack.shift() // Drop 1st entry as it's always the logStack function itself\n        console.log('%cCall stack:', log.LOG_STYLES.info.css, stack)\n        // log('info', 'Uib:logStack', 'Call stack:', this.stack())()\n    }\n\n    /** Makes a null or non-object into an object. If thing is already an object.\n     * If not null, moves \"thing\" to {payload:thing}\n     * @param {*} thing Thing to check\n     * @param {string} [property] property that \"thing\" is moved to if not null and not an object. Default='payload'\n     * @returns {!object} _\n     */\n    makeMeAnObject(thing, property) {\n        if (!property) property = 'payload'\n        if (typeof property !== 'string') {\n            log('warn', 'uibuilder:makeMeAnObject', `WARNING: property parameter must be a string and not: ${typeof property}`)()\n            property = 'payload'\n        }\n        let out = {}\n        if ( thing !== null && thing.constructor.name === 'Object' ) {\n            out = thing\n        } else if (thing !== null) {\n            out[property] = thing\n        }\n        return out\n    } // --- End of make me an object --- //\n\n    /** Navigate to a new page or a new route (hash)\n     * @param {string} url URL to navigate to. Can be absolute or relative (to current page) or just a hash for a route change\n     * @returns {Location} The new window.location string\n     */\n    navigate(url) {\n        if (url) window.location.href = url\n        return window.location\n    }\n\n    /** Create and return a randomised UUID\n     * Uses the browsers crypto library if available (newer browsers)\n     * or something based on the timestamp and a random number\n     * @returns {string} The UUID\n     */\n    randomUUID() {\n        return (typeof crypto !== 'undefined' && crypto.randomUUID)\n            ? crypto.randomUUID()\n            : `${Date.now()}-${Math.random().toString(36)\n                .substring(2, 11)}`\n    }\n\n    /** Wrap a provided variable in a proxy object so that it can be used reactively\n     * @param {*} srcvar The source variable to wrap\n     * @returns {Proxy} A proxy object that can be used reactively\n     */\n    reactive(srcvar) {\n        return createReactive(srcvar)\n    }\n\n    /** Get the Reactive class for advanced usage\n     * @returns {Function} The Reactive class constructor\n     * @example\n     * const ReactiveClass = uib.getReactiveClass()\n     * const reactiveInstance = new ReactiveClass(data, customEventDispatcher)\n     * const proxy = reactiveInstance.create()\n     */\n    getReactiveClass() {\n        return Reactive\n    }\n\n    // ! TODO change ui uib-* attributes to use this\n    /** Convert a string attribute into an variable/constant reference\n     * Used to resolve data sources in attributes\n     * @param {string} path The string path to resolve, must be relative to the `window` global scope\n     * @returns {*} The resolved data source or null\n     */\n    resolveDataSource(path) {\n        try {\n            const parts = path.split(/[\\.\\[\\]\\'\\\"]/).filter(Boolean)\n            let data = window\n            for (const part of parts) {\n                data = data?.[part]\n            }\n            return data\n        } catch (error) {\n            // console.error('Error resolving data source:', error)\n            log('error', 'uibuilder:resolveDataSource', `Error resolving data source \"${path}\", returned 'null'. ${error.message}`)()\n            return null\n        }\n    }\n\n    /** Fast but accurate number rounding (https://stackoverflow.com/a/48764436/1309986 solution 2)\n     * Half away from zero method (AKA \"commercial\" rounding), most common type\n     * @param {number} num The number to be rounded\n     * @param {number} decimalPlaces Number of DP's to round to\n     * @returns {number} Rounded number\n     */\n    round(num, decimalPlaces) {\n        const p = Math.pow(10, decimalPlaces || 0)\n        const n = (num * p) * (1 + Number.EPSILON)\n        return Math.round(n) / p\n    }\n\n    /** Set the default originator. Set to '' to ignore. Used with uib-sender.\n     * @param {string} [originator] A Node-RED node ID to return the message to\n     */\n    setOriginator(originator = '') {\n        this.set('originator', originator)\n    } // ---- End of setOriginator ---- //\n\n    /** HTTP Ping/Keep-alive - makes a call back to uibuilder's ExpressJS server and receives a 204 response\n     * Can be used to keep sessions alive.\n     * @example\n     *   uibuilder.setPing(2000) // repeat every 2 sec. Re-issue with ping(0) to turn off repeat.\n     *   uibuilder.onChange('ping', function(data) {\n     *      console.log('pinger', data)\n     *   })\n     * @param {number} ms Repeat interval in ms\n     */\n    setPing(ms = 0) {\n        const oReq = new XMLHttpRequest()\n        oReq.addEventListener('load', () => {\n            const headers = (oReq.getAllResponseHeaders()).split('\\r\\n')\n            const elapsedTime = Number(new Date()) - Number((oReq.responseURL.split('='))[1])\n            this.set('ping', {\n                success: !!((oReq.status === 201) || (oReq.status === 204)), // true if one of the listed codes else false\n                status: oReq.status,\n                headers: headers,\n                url: oReq.responseURL,\n                elapsedTime: elapsedTime,\n            })\n        })\n\n        if (this.#pingInterval) {\n            clearInterval(this.#pingInterval)\n            this.#pingInterval = undefined\n        }\n\n        oReq.open('GET', `${this.httpNodeRoot}/uibuilder/ping?t=${Number(new Date())}`)\n        oReq.send()\n\n        if (ms > 0) {\n            this.#pingInterval = setInterval(() => {\n                oReq.open('GET', `${this.httpNodeRoot}/uibuilder/ping?t=${Number(new Date())}`)\n                oReq.send()\n            }, ms)\n        }\n    } // ---- End of ping ---- //\n\n    /** Get the current call stack as an array of objects containing file, function, line, column, and raw information.\n     * Sheesh! Sometimes JavaScript is a PAIN. The stack property of an Error object is not yet an official standard\n     * and is implemented differently across browsers. So we have to do a bunch of parsing to try to get a consistent\n     * output across browsers. We will attempt to parse the stack trace in Chromium, Firefox, and Safari formats, and\n     * return an array of objects with the same properties for each line of the stack trace.\n     * @returns {Array<{{file:string,function:string,line:number,column:number,raw:string}}>} Stack array\n     */\n    stack() {\n        /** Map a Chromium stack trace line to an object with function, file, line, and column properties.\n         * @param {string} line Input stack trace line from Chromium, e.g. \"    at myFunction (http://example.com/script.js:10:15)\"\n         * @param {string} [raw] Optional raw line to include in output if parsing fails. Defaults to the input line.\n         * @returns {object} An object with function, file, line, column, and raw properties extracted from the stack trace line\n         */\n        function _stackMapChromium(line) {\n            // console.log(arguments, arguments.length === 2 ? arguments[1] : '--no raw--')\n            let raw\n            if (arguments.length === 2) {\n                // console.log('Using provided raw line for output: ', arguments[1])\n                raw = arguments[1]\n            } else {\n                // console.log('No raw line provided, using input line for output: ', line)\n                raw = line\n            }\n\n            // Check line for \"at <\" - if so, there is no function name, so we need to adjust the regex to account for that\n            if (line.includes('at <')) {\n                // No function name case\n                line = line.replace('at <', 'at anonymous (<') + ')' // Replace with a placeholder function name so that the regex can still capture the file, line, and column\n            }\n            const match = line.match(/at\\s+(.*)\\s+\\((.*):(\\d+):(\\d+)\\)/) || line.match(/at\\s+(.*):(\\d+):(\\d+)/)\n            if (match) {\n                return {\n                    function: match[1],\n                    file: match[2],\n                    line: parseInt(match[3], 10),\n                    column: parseInt(match[4], 10),\n                    raw,\n                }\n            }\n            return { raw, }\n        }\n        /** Map a Firefox stack trace line to a Chromium-like format for easier parsing.\n         * @param {string} line Input stack trace line from Firefox, e.g. \"myFunction@http://example.com/script.js:10:15\"\n         * @returns {object} An object with function, file, line, column, and raw properties extracted from the stack trace line\n         */\n        function _stackMapFirefox(line) {\n            const raw = line\n            line = line\n                .replace(/^@/, 'anonymous@')\n                .replace(/debugger eval code/g, '<anonymous>')\n                .replace(/^(.*)@(.*):(\\d+):(\\d+)$/, '    at $1 ($2:$3:$4)')\n            return _stackMapChromium(line, raw)\n        }\n        /** Map a Safari stack trace line to a Chromium-like format for easier parsing.\n         * Note that Safari does not include line or column numbers, so these will be set to 0.\n         *      It does not even include the calling script file name :(\n         * @param {string} line Input stack trace line from Safari, e.g. \"myFunction@http://example.com/script.js\"\n         * @returns {object} An object with function, file (<safari-unknown>), line (0), column (0), and raw properties extracted from the stack trace line\n         */\n        function _stackMapSafari(line) {\n            const raw = line\n            line = line\n                .replace(/^global code@/, 'anonymous@')\n                .replace(/^(.*)@$/, '    at $1 (<safari-unknown>:0:0)')\n            return _stackMapChromium(line, raw)\n        }\n\n        let stack = (new Error()).stack\n        let type = 'unknown'\n        // Is this a Safari browser? Safari has a different stack trace format and doesn't include the \"at\" keyword, so we need to adjust for that\n        if (stack.includes('at ')) {\n            // Chromium case - we can parse the stack as is, dropping the first 2 lines which are just \"Error\" and the current function\n            type = 'chromium'\n            stack = stack.split('\\n').slice(2)\n            stack = stack.map(_stackMapChromium)\n        } else if (stack.endsWith('@')) {\n            // Safari case - it is cr@p and does not include line or column numbers, so we will just return the raw stack lines as the file and function with line and column as null. We also need to drop the first line which is just \"Error\"\n            type = 'safari'\n            // console.trace() // Does not trace other than this fn on Safari unlike other browsers.\n            stack = stack.split('\\n').slice(1) // Remove the first line\n            stack = stack.map(_stackMapSafari)\n        } else if (stack.includes('@')) {\n            // else is this Firefox? Firefox also has a different format, It uses \"@\" instead of \"at\" and doesn't include the column number, so we need to adjust for that as well\n            type = 'firefox'\n            // Firefox case - we will replace \"@\" with \"at\" and add a placeholder column number to make it compatible with our regex parsing below\n            stack = stack.split('\\n').slice(1, -1) // Remove the first & last lines\n            stack = stack.map(_stackMapFirefox)\n        } else {\n            // Unknown format, return raw stack as a single entry\n            return [{ raw: stack, }]\n        }\n\n        return stack\n    }\n\n    /** Convert JSON to Syntax Highlighted HTML\n     * @param {object} json A JSON/JavaScript Object\n     * @returns {html} Object reformatted as highlighted HTML\n     */\n    syntaxHighlight(json) {\n        return syntaxHighlight(json)\n    } // --- End of syntaxHighlight --- //\n\n    /** Returns true/false or a default value for truthy/falsy and other values\n     * @param {string|number|boolean|*} val The value to test\n     * @param {any} deflt Default value to use if the value is not truthy/falsy\n     * @returns {boolean|any} The truth! Or the default\n     */\n    truthy(val, deflt) {\n        let ret\n        if (['on', 'On', 'ON', 'true', 'True', 'TRUE', '1', true, 1].includes(val)) ret = true\n        else if (['off', 'Off', 'OFF', 'false', 'False', 'FALSE', '0', false, 0].includes(val)) ret = false\n        else ret = deflt\n        return ret\n    }\n\n    /** Joins all arguments as a URL string\n     * see http://stackoverflow.com/a/28592528/3016654\n     * since v1.0.10, fixed potential double // issue\n     * arguments {string} URL fragments\n     * @returns {string} _\n     */\n    urlJoin() {\n        const paths = Array.prototype.slice.call(arguments)\n        const url = '/' + paths.map(function (e) {\n            return e.replace(/^\\/|\\/$/g, '')\n        })\n            .filter(function (e) {\n                return e\n            })\n            .join('/')\n        return url.replace('//', '/')\n    } // ---- End of urlJoin ---- //\n\n    /** Turn on/off/toggle sending URL hash changes back to Node-RED\n     * @param {string|number|boolean|undefined} [toggle] Optional on/off/etc\n     * @returns {boolean} True if we will send a msg to Node-RED on a hash change\n     */\n    watchUrlHash(toggle) {\n        this.#sendUrlHash = this.truthy(toggle, this.#sendUrlHash !== true)\n        return this.#sendUrlHash\n    }\n\n    /** DEPRECATED FOR NOW - wasn't working properly.\n     * Is the chosen CSS Selector currently visible to the user? NB: Only finds the FIRST element of the selection.\n     * Requires IntersectionObserver (available to all mainstream browsers from early 2019)\n     * Automatically sends a msg back to Node-RED.\n     * Requires the element to already exist.\n     * @returns {false} False if not visible\n     */\n    elementIsVisible() {\n        const info = 'elementIsVisible has been temporarily DEPRECATED as it was not working correctly and a fix is complex'\n        log('error', 'uib:elementIsVisible', info)()\n        this.send({ payload: 'elementIsVisible has been temporarily DEPRECATED as it was not working correctly and a fix is complex', })\n        return false\n    } // --- End of elementIsVisible --- //\n\n    // #endregion -------- -------- -------- //\n\n    // #region ------- UI handlers --------- //\n\n    // #region -- Direct to _ui --\n    // ! NOTE: Direct assignments change the target `this` to here. Use with caution\n    // However, also note that the window/jsdom and the window.document\n    // references are now static in _ui so not impacted by this.\n\n    /** Simplistic jQuery-like document CSS query selector, returns an HTML Element\n     * NOTE that this fn returns the element itself. Use $$ to get the properties of 1 or more elements.\n     * If the selected element is a <template>, returns the first child element.\n     * type {HTMLElement}\n     * @param {string} cssSelector A CSS Selector that identifies the element to return\n     * @returns {HTMLElement|null} Selected HTML element or null\n     */\n    $ = _ui.$\n\n    /** CSS query selector that returns ALL found selections. Matches the Chromium DevTools feature of the same name.\n     * NOTE that this fn returns an array showing the PROPERTIES of the elements whereas $ returns the element itself\n     * @param {string} cssSelector A CSS Selector that identifies the elements to return\n     * @returns {HTMLElement[]} Array of DOM elements/nodes. Array is empty if selector is not found.\n     */\n    $$ = _ui.$$\n\n    /** Reference to the full ui library */\n    $ui = _ui\n\n    /** Add 1 or several class names to an element\n     * @param {string|string[]} classNames Single or array of classnames\n     * @param {HTMLElement} el HTML Element to add class(es) to\n     */\n    addClass = _ui.addClass\n\n    /** Apply a source template tag to a target html element\n     * NOTES:\n     * - styles in ALL templates are accessible to all templates.\n     * - scripts in templates are run AT TIME OF APPLICATION (so may run multiple times).\n     * - scripts in templates are applied in order of application, so variables may not yet exist if defined in subsequent templates\n     * @param {HTMLElement} source The source element\n     * @param {HTMLElement} target The target element\n     * @param {boolean} onceOnly If true, the source will be adopted (the source is moved)\n     */\n    applyTemplate = _ui.applyTemplate\n\n    /** Column metadata object definition\n     * @typedef columnDefinition\n     * @property {number} index The column index number\n     * @property {boolean} hasName Whether the column has a defined name or not\n     * @property {string} title The title of the column. Shown in the table header row\n     * @property {string=} name Optional. A defined column name that will be added as the `data-col-name` to all cells in the column if defined\n     * @property {string|number=} key Optional. A key value (currently unused)\n     * @property {\"string\"|\"date\"|\"number\"|\"html\"=} dataType FOR FUTURE USE. Optional. What type of data will this column contain?\n     * @property {boolean=} editable FOR FUTURE USE. Optional. Can cells in this column be edited?\n     */\n\n    /** Builds an HTML table from an array (or object) of objects\n     * 1st row is used for columns.\n     * If an object of objects, inner keys are used to populate th/td `data-col-name` attribs.\n     * @param {Array<object>|object} data Input data array or object\n     * @param {object} opts Table options\n     *   @param {Array<columnDefinition>=} opts.cols Column metadata. If not provided will be derived from 1st row of data\n     * @returns {HTMLTableElement|HTMLParagraphElement} Output HTML Element\n     */\n    buildHtmlTable(data, opts = {}) {\n        return _ui.buildHtmlTable(data, opts)\n    }\n\n    /** Directly add a table to a parent element.\n     * @param {Array<object>|Array<Array>|object} data  Input data array or object. Object of objects gives named rows. Array of objects named cols. Array of arrays no naming.\n     * @param {object} [opts] Build options\n     *   @param {Array<columnDefinition>=} opts.cols Column metadata. If not provided will be derived from 1st row of data\n     *   @param {HTMLElement|string} opts.parent Default=body. The table will be added as a child instead of returned. May be an actual HTML element or a CSS Selector\n     *   @param {boolean=} opts.allowHTML Optional, default=false. If true, allows HTML cell content, otherwise only allows text. Always sanitise HTML inputs\n     */\n    createTable(data = [], opts = { parent: 'body', }) {\n        _ui.createTable(data, opts)\n    }\n\n    /** Converts markdown text input to HTML if the Markdown-IT library is loaded\n     * Otherwise simply returns the text\n     * @param {string} mdText The input markdown string\n     * @returns {string} HTML (if Markdown-IT library loaded and parse successful) or original text\n     */\n    convertMarkdown(mdText) {\n        return _ui.convertMarkdown(mdText)\n    }\n\n    /** ASYNC: Include HTML fragment, img, video, text, json, form data, pdf or anything else from an external file or API\n     * Wraps the included object in a div tag.\n     * PDF's, text or unknown MIME types are also wrapped in an iFrame.\n     * @param {string} url The URL of the source file to include\n     * @param {object} uiOptions Object containing properties recognised by the _uiReplace function. Must at least contain an id\n     * param {string} uiOptions.id The HTML ID given to the wrapping DIV tag\n     * param {string} uiOptions.parentSelector The CSS selector for a parent element to insert the new HTML under (defaults to 'body')\n     */\n    async include(url, uiOptions) {\n        await _ui.include(url, uiOptions)\n    }\n\n    /** Attach a new remote script to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} url The url to be used in the script src attribute\n     */\n    loadScriptSrc(url) {\n        _ui.loadScriptSrc(url)\n    }\n\n    /** Attach a new remote stylesheet link to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} url The url to be used in the style link href attribute\n     */\n    loadStyleSrc(url) {\n        _ui.loadStyleSrc(url)\n    }\n\n    /** Attach a new text script to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} textFn The text to be loaded as a script\n     */\n    loadScriptTxt(textFn) {\n        _ui.loadScriptTxt(textFn)\n    }\n\n    /** Attach a new text stylesheet to the end of HEAD synchronously\n     * NOTE: It takes too long for most scripts to finish loading\n     *       so this is pretty useless to work with the dynamic UI features directly.\n     * @param {string} textFn The text to be loaded as a stylesheet\n     */\n    loadStyleTxt(textFn) {\n        _ui.loadStyleTxt(textFn)\n    }\n\n    /** Load a dynamic UI from a JSON web reponse\n     * @param {string} url URL that will return the ui JSON\n     */\n    loadui(url) {\n        _ui.loadui(url)\n    }\n\n    /** Remove All, 1 or more class names from an element\n     * @param {undefined|null|\"\"|string|string[]} classNames Single or array of classnames. If undefined, \"\" or null, remove all classes\n     * @param {HTMLElement} el HTML Element to add class(es) to\n     */\n    removeClass = _ui.removeClass\n\n    /** Replace or add an HTML element's slot from text or an HTML string\n     * WARNING: Executes <script> tags! And will process <style> tags.\n     * Will use DOMPurify if that library has been loaded to window.\n     * param {*} ui Single entry from the msg._ui property\n     * @param {Element} el Reference to the element that we want to update\n     * @param {*} slot The slot content we are trying to add/replace (defaults to empty string)\n     */\n    replaceSlot(el, slot) {\n        _ui.replaceSlot(el, slot)\n    }\n\n    /** Replace or add an HTML element's slot from a Markdown string\n     * Only does something if the markdownit library has been loaded to window.\n     * Will use DOMPurify if that library has been loaded to window.\n     * @param {Element} el Reference to the element that we want to update\n     * @param {*} component The component we are trying to add/replace\n     */\n    replaceSlotMarkdown(el, component) {\n        _ui.replaceSlotMarkdown(el, component)\n    }\n\n    /** Sanitise HTML to make it safe - if the DOMPurify library is loaded\n     * Otherwise just returns that HTML as-is.\n     * @param {string} html The input HTML string\n     * @returns {string} The sanitised HTML or the original if DOMPurify not loaded\n     */\n    sanitiseHTML(html) {\n        return _ui.sanitiseHTML(html)\n    }\n\n    /** Creates and displays an overlay window with customizable content and behavior\n     * @param {object} options - Configuration options for the overlay\n     *   @param {string} [options.content] - Main content (text or HTML) to display\n     *   @param {string} [options.title] - Optional title above the main content\n     *   @param {string} [options.icon] - Optional icon to display left of title (HTML or text)\n     *   @param {string} [options.type] - Overlay type: 'success', 'info', 'warning', or 'error'\n     *   @param {boolean} [options.showDismiss] - Whether to show dismiss button (auto-determined if not set)\n     *   @param {number|null} [options.autoClose] - Auto-close delay in seconds (null for no auto-close)\n     *   @param {boolean} [options.time] - Show timestamp in overlay (default: true)\n     * @returns {object} Object with close() method to manually close the overlay\n     */\n    showOverlay(options) {\n        return _ui.showOverlay(options)\n    }\n\n    /** Add table event listener that returns the text or html content of either the full row or a single cell\n     * NOTE: Assumes that the table has a `tbody` element.\n     * If cells have a `data-col-name` attribute, it will be used in the output as the column name.\n     * @example tblAddListener('#eltest-tbl-table', {}, myVar)\n     * @example tblAddListener('#eltest-tbl-table', {eventScope: 'cell'}, myVar2)\n     *\n     * @param {string} tblSelector The table CSS Selector\n     * @param {object} [options] Additional options. Default={}\n     *   @param {\"row\"|\"cell\"=} options.eventScope Optional, default=row. Return data for either the whole row (as an object) or for the single cell clicked\n     *   @param {\"text\"|\"html\"=} options.returnType Optional, default=text. Return text or html data\n     *   @param {number=} options.pad Optional, default=3. Will be used to front-pad unnamed column references with zeros. e.g. 3 => \"C002\"/\"C012\"/\"C342\"\n     *   @param {boolean=} options.send Optional, default=true. If uibuilder is present, will automatically send a message back to Node-RED.\n     *   @param {string|number=} options.logLevel Optional, default=3/info. Numeric or string log level matching uibuilder's log levels.\n     *   @param {string} [options.eventType] Optional, default=click. What event to listen for.\n     * @param {object=} out A variable reference that will be updated with the output data upon a click event\n     */\n    tblAddListener(tblSelector, options = {}, out = {}) {\n        _ui.tblAddListener(tblSelector, options, out)\n    }\n\n    /** Adds (or replaces) a single row in an existing table>tbody\n     * NOTE: Row numbers use the rowIndex property of the row element.\n     * @param {string|HTMLTableElement} tbl Either a CSS Selector for the table or a reference to the HTML Table Element\n     * @param {object|Array} rowData A single row of column/cell data\n     * @param {object} [options] Additional options\n     * @param {number=} options.body Optional, default=0. The tbody section to add the row to.\n     * @param {boolean=} options.allowHTML Optional, default=false. If true, allows HTML cell content, otherwise only allows text. Always sanitise HTML inputs\n     * @param {string=} options.rowId Optional. HTML element ID for the added row\n     * @param {number=} options.afterRow Optional. If provided, the new row will be added after this row number\n     * @param {number=} options.beforeRow Optional. If provided, the new row will be added before this row number. Ignored if afterRow is provided\n     * @param {number=} options.replaceRow Optional. If provided, the specified row will be REPLACED instead of added. Ignored if afterRow or beforeRow is provided\n     * @param {Array<columnDefinition>} [options.cols] Optional. Data about each column. If not provided, will be calculated from the table\n     *\n     * @returns {HTMLTableRowElement} Reference to the newly added row. Use the `rowIndex` prop for the row number\n     */\n    tblAddRow(tbl, rowData = {}, options = {}) {\n        return _ui.tblAddRow(tbl, rowData, options)\n    }\n\n    /** Remove a row from an existing table\n     * @param {string|HTMLTableElement} tbl Either a CSS Selector for the table or a reference to the HTML Table Element\n     * @param {number} rowIndex The row number to remove (1st row is 0, last row is -1)\n     * @param {object} [options] Additional options\n     *  @param {number=} options.body Optional, default=0. The tbody section to add the row to.\n     */\n    tblRemoveRow(tbl, rowIndex, options = {}) {\n        _ui.tblRemoveRow(tbl, rowIndex, options)\n    }\n\n    /** Show a pop-over \"toast\" dialog or a modal alert\n     * Refs: https://www.w3.org/WAI/ARIA/apg/example-index/dialog-modal/alertdialog.html,\n     *       https://www.w3.org/WAI/ARIA/apg/example-index/dialog-modal/dialog.html,\n     *       https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/\n     * @param {\"notify\"|\"alert\"|null} type Dialog type. If null, invalid or not provided, defaults to \"notify\".\n     * @param {object|null} ui Standardised ui data. If not provided, defaults to {noAutohide:true,modal:true,appendToast:false}\n     * @param {object} [msg] msg.payload/msg.topic - only used if payload is a string. Optional.\n     * @returns {void}\n     * @example\n     * Ui.showDialog('notify', { title: 'Hello', content: 'This is a notification', noAutohide: true, appendToast: true })\n     * @example\n     * Ui.showDialog('alert', null, msg)\n     */\n    showDialog(type, ui, msg) {\n        _ui.showDialog(type, ui, msg)\n    }\n\n    /** Directly manage UI via JSON\n     * @param {object} json Either an object containing {_ui: {}} or simply simple {} containing ui instructions\n     */\n    ui(json) {\n        _ui.ui(json)\n    }\n\n    /** Get data from the DOM. Returns selection of useful props unless a specific prop requested.\n     * @param {string} cssSelector Identify the DOM element to get data from\n     * @param {string} [propName] Optional. Specific name of property to get from the element\n     * @returns {Array<*>} Array of objects containing either specific requested property or a selection of useful properties\n     */\n    uiGet(cssSelector, propName = null) {\n        return _ui.uiGet(cssSelector, propName)\n    }\n\n    /** Enhance an HTML element that is being composed with ui data\n     *  such as ID, attribs, event handlers, custom props, etc.\n     * @param {*} el HTML Element to enhance\n     * @param {*} component Individual uibuilder ui component spec\n     */\n    uiEnhanceElement(el, component) {\n        _ui.uiEnhanceElement(el, component)\n    }\n\n    // #endregion -- direct to _ui --\n\n    // ! TODO: Rework attrib handling to allow for uib-* and data-uib-* AND :* attributes\n    //   See other bookmarks as well\n\n    /** DOM Mutation observer callback to watch for new/amended elements with uib-* or data-uib-* attributes\n     * WARNING: Mutation observers can receive a LOT of mutations very rapidly. So make sure this runs as fast\n     *          as possible.\n     * Observer is set up in the start() function\n     * @param {MutationRecord[]} mutations Array of Mutation Records\n     * @private\n     */\n    _uibAttribObserver(mutations/* , observer */) {\n        const mlen = mutations.length\n        for (let i = 0; i < mlen; i++) {\n            const m = mutations[i]\n            // log('trace', 'uibuilder:_uibAttribObserver', 'Mutations ', m)()\n            // Deal with attribute changes\n            if (m.attributeName && this.isUibAttribute(m.attributeName)) {\n                // log(0, 'attribute mutation', m.attributeName, m.target.getAttribute(m.attributeName), m.oldValue, m )()\n                this._uibAttrScanOne(m.target)\n            } else if (m.addedNodes.length > 0) {\n                // And deal with newly added elements (e.g. from route change)\n                const nlen = m.addedNodes.length\n                for (let i = 0; i < nlen; i++) {\n                    const n = m.addedNodes[i]\n                    // Check if the added node itself has uib attributes\n                    try {\n                        if (n.attributes && [...n.attributes].some(a => this.isUibAttribute(a.name))) {\n                            this._uibAttrScanOne(n)\n                        }\n                    } catch (e) {} // Nodes might not always have attributes\n                    // And get any children of the added element that have uib attribs\n                    // WARNING: This only selects KNOWN attribute names, not all prefixes.\n                    if (n.querySelectorAll) {\n                        const elToCheck = n.querySelectorAll(this.#uibAttrSel)\n                        const len = elToCheck.length\n                        for (let i = 0; i < len; i++) {\n                            this._uibAttrScanOne(elToCheck[i])\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /** Process a uib-topic attribute by setting up a topic listener and applying received msgs to the element\n     *  as per the msg properties (e.g. msg.payload, msg.attributes, msg.dataset, etc)\n     * @param {HTMLElement} el The element to process\n     * @param {string} topic The msg topic string to watch for\n     * @private\n     */\n    _processUibTopic(el, topic) {\n        // Create a topic listener\n        this.onTopic(topic, (msg) => {\n            // log('trace', 'uibuilder:_uibAttrScanOne', `Msg with topic \"${topic}\" received. msg content: `, msg)()\n            msg._uib_processed_by = '_uibAttrScanOne' // record that this has already been processed\n\n            // Process msg.attributes\n            if (Object.prototype.hasOwnProperty.call(msg, 'attributes')) {\n                try {\n                    for (const [k, v] of Object.entries(msg.attributes)) {\n                        el.setAttribute(k, v)\n                    }\n                } catch (e) {\n                    log(0, 'uibuilder:attribute-processing', 'Failed to set attributes. Ensure that msg.attributes is an object containing key/value pairs with each key a valid attribute name. Note that attribute values have to be a string.')()\n                }\n            }\n\n            // Process msg.dataset\n            if (Object.prototype.hasOwnProperty.call(msg, 'dataset')) {\n                console.log('uibuilder:dataset-processing', 'Processing dataset for element', el, msg.dataset)\n                try {\n                    for (const [key, value] of Object.entries(msg.dataset)) {\n                        // Convert to kebab-case for dataset\n                        // const kebabKey = k.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n                        // el.dataset[kebabKey] = v\n                        el.dataset[key] = value\n                    }\n                } catch (e) {\n                    log('error', 'uibuilder:dataset-processing', 'Failed to set dataset. Ensure that msg.dataset is an object containing key/value pairs with each key a valid dataset name. Note that dataset values have to be a string.')()\n                }\n            }\n\n            // Process msg.value (or set checked if boolean - for checkboxes)\n            // TODO Move this to a common function\n            const hasChecked = Object.prototype.hasOwnProperty.call(msg, 'checked')\n            const hasValue = Object.prototype.hasOwnProperty.call(msg, 'value')\n            if ( hasValue || hasChecked ) {\n                if (el.type && (el.type === 'checkbox' || el.type === 'radio')) {\n                    if (hasChecked) el.checked = this.truthy(msg.checked, false)\n                    else if (hasValue) el.checked = this.truthy(msg.value, false)\n                } else {\n                    if (hasValue) el.value = msg.value\n                    else if (hasChecked) el.value = this.truthy(msg.checked, false)\n                }\n            }\n\n            // TODO (MAYBE) Process msg.classes and msg.styles. msg.props (for non-string data)?\n\n            // If el has a `content` attrib, we must apply as text not html\n            if (el.hasAttribute('content')) {\n                if (Object.prototype.hasOwnProperty.call(msg, 'payload')) el.setAttribute('content', msg.payload)\n            } else {\n                // Process msg.payload (applied as slot HTML) - NB: Will process <script> & <style>\n                if (Object.prototype.hasOwnProperty.call(msg, 'payload')) this.replaceSlot(el, msg.payload)\n            }\n        })\n    }\n\n    /** Resolve a dotted/bracketed property path on an object\n     * e.g. resolveNestedPath(obj, 'a.b[\"c\"]') => obj.a.b.c\n     * @param {object} obj The object to resolve from\n     * @param {string} path The property path string (e.g. 'myvar.aprop' or 'myvar[\"bprop\"]')\n     * @returns {*} The resolved value, or undefined if not found\n     * @private\n     */\n    _resolveNestedPath(obj, path) {\n        if (!obj || !path) return undefined\n        // Split on dots and bracket notation, filter out empty segments\n        const keys = path\n            .replace(/\\[[\"'`]?/g, '.')\n            .replace(/[\"'`]?\\]/g, '')\n            .split('.')\n            .filter(Boolean)\n        let current = obj\n        for (const key of keys) {\n            if (current == null) return undefined\n            current = current[key]\n        }\n        return current\n    }\n\n    /** Set a value at a dotted/bracketed property path on an object\n     * e.g. _setNestedPath(obj, 'a.b[\"c\"]', value) => obj.a.b.c = value\n     * Creates intermediate objects if they don't exist\n     * @param {object} obj The object to set the value on\n     * @param {string} path The property path string (e.g. 'myvar.aprop' or 'myvar[\"bprop\"]')\n     * @param {*} value The value to set\n     * @returns {boolean} True if successful, false otherwise\n     * @private\n     */\n    _setNestedPath(obj, path, value) {\n        if (!obj || !path) return false\n        // Split on dots and bracket notation, filter out empty segments\n        const keys = path\n            .replace(/\\[[\"'`]?/g, '.')\n            .replace(/[\"'`]?\\]/g, '')\n            .split('.')\n            .filter(Boolean)\n\n        // Navigate to the parent of the final key, creating objects as needed\n        let current = obj\n        for (let i = 0; i < keys.length - 1; i++) {\n            const key = keys[i]\n            if (current[key] == null || typeof current[key] !== 'object') {\n                current[key] = {}\n            }\n            current = current[key]\n        }\n\n        // Set the final property\n        const finalKey = keys[keys.length - 1]\n        current[finalKey] = value\n        return true\n    }\n\n    /** Process a uib-var attribute by evaluating the variable reference and applying it to the element\n     *  as per the msg properties (e.g. msg.payload, msg.attributes, msg.dataset, etc).\n     *  Supports deep property paths such as \"myvar.aprop\" or \"myvar['bprop']\".\n     * @param {HTMLElement} el The element to process\n     * @param {string} varName The variable name (optionally with property path) to watch for\n     * @private\n     */\n    async _processUibVar(el, varName) {\n        // Determine the root property and any nested sub-path\n        // e.g. \"myvar.aprop\" => rootProp=\"myvar\", subPath=\"aprop\"\n        // e.g. \"myvar['bprop'].x\" => rootProp=\"myvar\", subPath=\"'bprop'].x\"\n        const dotIdx = varName.indexOf('.')\n        const bracketIdx = varName.indexOf('[')\n        // Find the earliest separator\n        let sepIdx = -1\n        if (dotIdx >= 0 && bracketIdx >= 0) sepIdx = Math.min(dotIdx, bracketIdx)\n        else if (dotIdx >= 0) sepIdx = dotIdx\n        else if (bracketIdx >= 0) sepIdx = bracketIdx\n\n        const hasSubPath = sepIdx > 0\n        const rootProp = hasSubPath ? varName.substring(0, sepIdx) : varName\n\n        const doVar = (rootValue, hasSubPath) => {\n            let value = hasSubPath ? this._resolveNestedPath(this, varName) : rootValue\n            // console.log(`\uD83E\uDEB2[uibuilder:_processUibVar] Variable \"${varName}\" changed. New value:`, value)\n            // log('trace', 'uibuilder:_processUibVar', `Variable \"${varName}\" changed. New value: `, value)()\n            if (typeof value !== 'object') {\n                value = {\n                    payload: value,\n                }\n            }\n            // Deal with different element types:\n            if (Object.prototype.hasOwnProperty.call(value, 'payload')) {\n                // Skip update when payload is null or undefined to avoid setting attributes\n                // to the literal string \"undefined\" (e.g. <link rel=\"icon\"> href=\"undefined\").\n                if (value.payload == null) return\n                if (el.hasAttribute('content')) {\n                    // If el has a `content` attrib, we must apply as text not html\n                    el.setAttribute('content', value.payload)\n                } else if (el.hasAttribute('rel')) {\n                    // If it has a `rel` attribute, we have to set the `href`\n                    el.setAttribute('href', value.payload)\n                } else {\n                    // Otherwise, we replace the innerHTML\n                    this.replaceSlot(el, value.payload)\n                }\n            }\n        }\n\n        // Create a uibuilder managed variable watcher on the root property\n        // When the root property changes, resolve the full nested path to get the value\n        this.onChange(rootProp, (rootValue) => {\n            doVar(rootValue, hasSubPath)\n        })\n        // and do it now\n        doVar(await this.evaluateWithRetry(rootProp, this, {}), hasSubPath)\n    }\n\n    // ! EXPERIMENTAL - not fully working. Is not reactive.\n    /** Process a uib-if attribute by safely evaluating a JavaScript expression that returns true/false.\n     * If true (the default), the element's content is visible. If false, the content is hidden.\n     * Uses display style rather than removing content so the element can be shown again later.\n     * The expression can reference uibuilder managed variables (e.g. pageData.status) directly\n     * as well as global/window variables.\n     * @param {HTMLElement} el The element to process\n     * @param {string} expr The JavaScript expression to evaluate\n     * @private\n     */\n    async _processUibIf(el, expr) {\n        // /** Evaluate the expression using current managed variables and apply visibility\n        //  * @private\n        //  */\n        // const evaluate = () => {\n        //     // Skip if element has been removed from DOM\n        //     if (!el.isConnected) return\n        //     let result = true\n        //     try {\n        //         // Inject user-set managed variables as local parameters so they can be\n        //         // referenced directly in expressions (e.g. `pageData.status || pageData.since`).\n        //         // Only include names that are valid JS identifiers.\n        //         const varNames = Object.keys(this.#managedVars).filter(name => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))\n        //         const varValues = varNames.map(name => this[name])\n        //         // Also expose the uibuilder instance itself\n        //         varNames.push('uibuilder')\n        //         varValues.push(this)\n        //         result = (new Function(...varNames, `return (${expr})`))(...varValues)\n        //         console.log(`\uD83E\uDEB2[uibuilder:_processUibIf] Evaluated expression \"${expr}\" with result:`, result)\n        //     } catch (e) {\n        //         log('warn', 'uibuilder:_processUibIf', `Failed to evaluate uib-if expression \"${expr}\". Defaulting to true.`, e.message)()\n        //     }\n        //     // Coerce to boolean, default to true for non-boolean returns\n        //     if (typeof result !== 'boolean') result = this.truthy(result, true)\n        //     el.style.display = result ? '' : 'none'\n        // }\n        // // Evaluate immediately with whatever vars are available now\n        // setTimeout(() => {\n        //     evaluate()\n        // }, 300)\n        // // Re-evaluate whenever any managed variable changes (handles timing/late-set vars)\n        // document.addEventListener('uibuilder:propertyChanged', evaluate)\n        // const result = await this.evaluateWithRetry(expr, this, {})\n        const result = await this.evaluateWithRetry(expr, this, {})\n        // console.log(`\uD83E\uDEB2[uibuilder:_processUibIf] Final result for expression \"${expr}\":`, result)\n        el.style.display = result ? '' : 'none'\n    }\n\n    /** Creates a safe evaluator function for template (string) expressions\n     * - will retry several times if variables are not yet available, and defaults to false if still not successful after retries.\n     * @param {string} expression - The expression to evaluate (e.g., \"pageData.status || pageData.since\")\n     * @param {object} context - The context object containing variables (e.g., { pageData })\n     * @param {object} options - Configuration options\n     * @returns {Promise<boolean>} - Resolves to true/false\n     */\n    async evaluateWithRetry(expression, context, options = {}) {\n        const {\n            maxRetries = 3,\n            retryDelay = 300,\n            defaultValue = false,\n        } = options\n\n        // Create a safe evaluation function\n        const evaluator = this.createSafeEvaluator(expression)\n\n        for (let attempt = 0; attempt <= maxRetries; attempt++) {\n            try {\n                const result = evaluator(context)\n                // console.log(`\uD83E\uDEB2[uibuilder:evaluateWithRetry] Attempt ${attempt + 1} for expression \"${expression}\" with result:`, result)\n\n                // Convert to boolean and check if we got a meaningful result\n                // (not undefined/null on first attempts)\n                if (result !== undefined && result !== null) {\n                    // return Boolean(result)\n                    return result\n                }\n\n                // If this was the last attempt, return default\n                if (attempt === maxRetries) {\n                    return defaultValue\n                }\n\n                // Wait before retry\n                await this.sleep(retryDelay)\n            } catch (error) {\n                console.warn(`Evaluation attempt ${attempt + 1} failed:`, error.message)\n\n                if (attempt === maxRetries) {\n                    return defaultValue\n                }\n\n                await this.sleep(retryDelay)\n            }\n        }\n\n        return defaultValue\n    }\n\n    /** Creates a sandboxed evaluator function for string expressions that can reference properties on a provided context object\n     * - Uses the Function constructor to create a new function with the context passed as an argument, and uses a with() block to allow direct access to context properties.\n     * - Catches and logs any errors during function creation, returning a safe default function that returns false if creation fails.\n     * @param {string} expression - The expression to evaluate\n     * @returns {Function} - Evaluator function\n     */\n    createSafeEvaluator(expression) {\n        // Validate the expression (basic security check)\n        if (typeof expression !== 'string' || expression.trim() === '') {\n            throw new Error('Expression must be a non-empty string')\n        }\n\n        // Create function with explicit parameter to avoid global scope access\n        // The context will be passed as an argument, making available variables explicit\n        try {\n            return new Function('context', `\n                // 'use strict';\n                with (context) {\n                    return (${expression});\n                }\n            `)\n        } catch (error) {\n            console.error('Failed to create evaluator:', error)\n            return () => false // Return safe default function\n        }\n    }\n\n    /** Promise-based (async) sleep utility\n     * @param {number} ms - Milliseconds to sleep\n     * @returns {Promise<void>} - Resolves after the specified time\n     */\n    sleep(ms) {\n        return new Promise(resolve => setTimeout(resolve, ms))\n    }\n\n    // ! EXPERIMENTAL\n    /** Process a uib-bind:* attribute by evaluating the bind value and applying it to the element as the named attribute\n     *  as per the msg properties (e.g. msg.payload, msg.attributes, msg.dataset, etc)\n     * @param {HTMLElement} el The element to process\n     * @param {string} bindName The name of the attribute to bind\n     * @param {string} bindValue The value to bind to the attribute\n     * @private\n     */\n    _processUibBind(el, bindName, bindValue) {\n        // log('print', 'uibuilder:_uibAttrScanOne', 'Processing uib-bind:', bindName, 'for element:', el)()\n        // treat the attribute value as a javascript function, run the function safely\n        let value = bindValue\n        try {\n            value = (new Function(`return (${bindValue})`))()\n            log('print', 'uibuilder:_uibAttrScanOne', 'SUCCESS 1 uib-bind attribute:', bindName, 'with value:', value)()\n        } catch (e) {\n            log('print', 'uibuilder:_uibAttrScanOne', '\uD83D\uDFE5Error 1 uib-bind attribute:', bindName, 'with value:', value)()\n            try {\n                console.log(globalThis)\n                value = globalThis[bindValue] ?? bindValue\n                // value = (new Function(`return (window.${attr.value})`))()\n                log('print', 'uibuilder:_uibAttrScanOne', 'SUCCESS 2 uib-bind attribute:', bindName, 'with value:', value)()\n            } catch (e) {\n                log('print', 'uibuilder:_uibAttrScanOne', '\uD83D\uDFE5Error 2 uib-bind attribute:', bindName, 'with value:', value)()\n            }\n        }\n\n        // set the attribute names by bindName to the value of the attribute\n        if (bindName && value) {\n            // Set the attribute to the value of the bindName\n            el.setAttribute(bindName, value)\n            // If the bindName is 'value', then also set the value of the element\n            if (bindName === 'value') el.value = value\n        } else {\n            log('warn', 'uibuilder:_uibAttrScanOne', 'Invalid uib-bind attribute:', bindName, 'with value:', value, 'for element:', el)()\n        }\n    }\n\n    /** Check a single HTML element for uib attributes and add auto-processors as needed.\n     * Understands uib-prefixed attributes (e.g. uib-topic, uib-var, uib-bind:*, uib-if, etc). Msgs received on the topic can have:\n     *   msg.payload - replaces innerHTML (but also runs <script>s and applies <style>s)\n     *   msg.attributes - An object containing attribute names as keys with attribute values as values. e.g. {title: 'HTML tooltip', href='#route03'}\n     * @param {Element} el HTML Element to check for uib-* or data-uib-* attributes\n     * @private\n     */\n    _uibAttrScanOne(el) {\n        // log('trace', 'uibuilder:_uibAttrScanOne', 'Setting up auto-processor for: ', el)()\n        // If the element doesn't exist any more or has no attributes - ignore\n        if (!el || !el.attributes) {\n            // log('warn', 'uibuilder:_uibAttrScanOne', 'No element or no attributes found. Skipping.', el)()\n            return\n        }\n        // Get all of the element's attributes that are uib-specific\n        let uibAttribs = [...el.attributes].filter(attr => this.isUibAttribute(attr.name))\n        // If no uib attributes, then skip\n        if (uibAttribs.length === 0) {\n            // log('trace', 'uibuilder:_uibAttrScanOne', 'No uib attributes found. Skipping.', el)()\n            return\n        }\n        // Remove duplicates\n        uibAttribs = [...new Set(uibAttribs)]\n\n        // Process all of the found attributes\n        const alen = uibAttribs.length\n        for (let i = 0; i < alen; i++) {\n            const attr = uibAttribs[i]\n            if (attr?.name === 'uib-topic' || attr?.name === 'data-uib-topic') this._processUibTopic(el, attr.value)\n            else if (attr?.name === 'uib-var' || attr?.name === 'data-uib-var') this._processUibVar(el, attr.value)\n            else if (attr?.name === 'uib-if' || attr?.name === 'data-uib-if') this._processUibIf(el, attr.value)\n            // ! EXPERIMENTAL Check for uib-bind:* attributes\n            else if (attr?.name.startsWith('uib-bind:') || attr?.name.startsWith('data-uib-bind:') || attr?.name.startsWith(':')) {\n                // Get the bind name\n                const bindName = attr.name.replace(/^(uib-bind:|data-uib-bind:|:)/, '')\n                this._processUibBind(el, bindName, attr.value)\n            }\n        }\n    }\n\n    /** Check all children of an array of or a single HTML element(s) for uib attributes and add auto-processors as needed.\n     * WARNING: Can only check for KNOWN attrib names, not all as per the main processing.\n     * @param {Element|Element[]} parentEl HTML Element to check for uib-* or data-uib-* attributes\n     * @private\n     */\n    _uibAttrScanAll(parentEl) {\n        if (!Array.isArray(parentEl)) parentEl = [parentEl]\n        const len = parentEl.length\n        for (let i = 0; i < len; i++) {\n            const p = parentEl[i]\n            // ! WARNING: Only selects KNOWN attribute names, not all\n            const uibChildren = p.querySelectorAll(this.#uibAttrSel)\n            // log('trace', 'uibuilder:_uibAttrScanAll:forEach:children', 'p, uibChildren: ', p, uibChildren)()\n            if (uibChildren.length > 0) {\n                // console.log('existing elements uib attrib', uibChildren)\n                uibChildren.forEach((el) => {\n                    this._uibAttrScanOne(el)\n                })\n            }\n        }\n    }\n\n    /** Given a FileList array, send each file to Node-RED and return file metadata\n     * @param {HTMLInputElement} srcEl Reference to the source input element\n     * @param {boolean=} noSend If true, don't send the file to Node-RED. Default is to send.\n     * @returns {Array<object>} Metadata values from all files\n     * @private\n     */\n    _processFilesInput(srcEl, noSend = false) {\n        const value = []\n        const files = srcEl.files\n        const seqCount = files.length\n        let seq = 0\n        for (const file of files) {\n            const props = {}\n            seq++\n            // Walk through each file property\n            for (const prop in file) {\n                props[prop] = file[prop]\n            }\n            // Create a temp URL allowing access to download the file\n            // Automatically destroyed on page reload\n            props.tempUrl = window.URL.createObjectURL(file)\n\n            value.push(props)\n\n            const meta = { seq, seqCount, }\n            meta.id = srcEl.id\n            // meta.srcElIds.name = srcEl.name\n            if (srcEl.form) meta.formId = srcEl.form.id\n            meta.tempUrl = props.tempUrl\n            meta.data = srcEl.dataset\n\n            // Auto-upload to Node-RED over Socket.IO {id: target.id, name: target.name, formId: target.parent.formID,}\n            if (noSend !== true) this.uploadFile(file, meta)\n        }\n        return value\n    }\n\n    /** Easy creation/change of DOM elements, @see ./tinyDom.js */\n    // dom = dom\n\n    /** Attempt to get target attributs - can fail for certain target types, if so, returns empty object\n     * @param {HTMLElement} el Target element\n     * @returns {object} Array of key/value HTML attribute objects\n     */\n    getElementAttributes(el) {\n        const ignoreAttribs = ['class', 'id', 'name']\n        let attribs\n        try {\n            attribs = Object.assign({},\n                ...Array.from(el.attributes,\n                    ( { name, value, } ) => {\n                        if ( !ignoreAttribs.includes(name) ) {\n                            return ({ [name]: value, })\n                        }\n                        return undefined\n                    }\n                )\n            )\n        } catch (e) {}\n\n        return attribs\n    }\n\n    /** Check for CSS Classes and return as array if found or undefined if not\n     * @param {HTMLElement} el Target element\n     * @returns {Array|undefined} Array of class names\n     */\n    getElementClasses(el) {\n        let classes\n        try {\n            classes = Array.from(el.classList)\n        } catch (e) {}\n        return classes\n    }\n\n    /** Get target custom properties - only shows custom props not element default ones\n     * Excludes custom props starting with _\n     * @param {HTMLElement} el Target element\n     * @returns {object} Object of propname/value pairs\n     */\n    getElementCustomProps(el) {\n        const props = {}\n        Object.keys(el).forEach( (key) => {\n            if (key.startsWith('_')) return // Exclude private\n            props[key] = el[key]\n        })\n        return props\n    }\n\n    /** Check for el.value and el.checked. el.checked will also set the value return for ease of use.\n     * Only 2 input types use el.checked, different from all other input types - this is annoying.\n     * @param {HTMLElement} el HTML Element to be checked\n     * @returns {{value:boolean|null, checked:boolean|null}} Return null if properties not present, else the appropriate value\n     */\n    getFormElementValue(el) {\n        let value = null\n        let checked = null\n\n        switch (el.type) {\n            case 'checkbox':\n            case 'radio': {\n                value = checked = el.checked\n                // HTML does not normally return any value if not checked but we do for ease of use,\n                break\n            }\n\n            case 'select-multiple': {\n                // value = Array.from(el.selectedOptions).forEach( (sel) => sel.value )\n                value = Array.from(el.selectedOptions).map(option => option.value)\n                break\n            }\n\n            default: {\n                if (el.value) value = el.value\n\n                // Probably not really needed\n                if (el.checked) {\n                    value = checked = el.checked\n                    // HTML does not normally return any value if not checked but we do for ease of use,\n                }\n\n                // If the value is a valid number, use that instead of the text version - probably only applies to range inputs\n                if (el.valueAsNumber && !isNaN(el.valueAsNumber)) {\n                    value = el.valueAsNumber\n                }\n\n                break\n            }\n        }\n\n        return { value, checked, }\n    }\n\n    // ! TODO - Handle fieldsets\n    /** For HTML Form elements (e.g. input, textarea, select), return the details\n     * @param {HTMLFormElement} el Source form element\n     * @returns {object|null} Form element key details\n     */\n    getFormElementDetails(el) {\n        if (!el.type) {\n            log(1, 'uibuilder:getFormElementDetails', 'Cannot get form element details as this is not an input type element')()\n            return null\n        }\n\n        // Get or create a (hopefully) unique ID\n        const id = this.returnElementId(el)\n        if (!id) {\n            log(1, 'uibuilder:getFormElementDetails', 'Cannot get form element details as no id is present and could not be generated')()\n            return null\n        }\n\n        let { value, checked, } = this.getFormElementValue(el) // eslint-disable-line prefer-const\n\n        // This is now done in eventSend rather than here for consistency with non-form sends.\n        // For multi file input, get the file details as the value\n        // el.files is a FileList type & each entry is a File type - have to process these manually - stupid HTML!\n        // https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications\n        // if (el.type === 'file' && el.files.length > 0) {\n        //     // Walk through each file in the FileList, get the details and send the file to Node-RED\n        //     value = this._processFilesInput(el.files)\n        // }\n\n        const formDetails = {\n            id: id,\n            name: el.name,\n            valid: el.checkValidity(),\n            type: el.type,\n        }\n        if (value !== null) formDetails.value = value\n        if (checked !== null) formDetails.checked = checked\n\n        // If the form element has invalid content, try to report why\n        if (formDetails.valid === false) {\n            const v = el.validity\n            formDetails.validity = {\n                badInput: v.badInput === true ? v.badInput : undefined,\n                customError: v.customError === true ? v.customError : undefined,\n                patternMismatch: v.patternMismatch === true ? v.patternMismatch : undefined,\n                rangeOverflow: v.rangeOverflow === true ? v.rangeOverflow : undefined,\n                rangeUnderflow: v.rangeUnderflow === true ? v.rangeUnderflow : undefined,\n                stepMismatch: v.stepMismatch === true ? v.stepMismatch : undefined,\n                tooLong: v.tooLong === true ? v.tooLong : undefined,\n                tooShort: v.tooShort === true ? v.tooShort : undefined,\n                typeMismatch: v.typeMismatch === true ? v.typeMismatch : undefined,\n                valueMissing: v.valueMissing === true ? v.valueMissing : undefined,\n            }\n        }\n\n        // If any data-* attribs defined\n        if (Object.keys(el.dataset).length > 0) formDetails.data = el.dataset\n\n        return formDetails\n    }\n\n    /** Show a browser notification if possible.\n     * Config can be a simple string, a Node-RED msg (topic as title, payload as body)\n     * or a Notifications API options object + config.title string.\n     * @example uibuilder.notify( 'My simple message to the user' )\n     * @example uibuilder.notify( {topic: 'My Title', payload: 'My simple message to the user'} )\n     * @example uibuilder.notify( {title: 'My Title', body: 'My simple message to the user'} )\n     * @example // If config.return = true, a promise is returned.\n     * // The resolved promise is only returned if the notification is clicked by the user.\n     * // Can be used to send the response back to Node-RED\n     * uibuilder.notify(notifyConfig).then( res => uibuilder.eventSend(res) )\n     * @see https://developer.mozilla.org/en-US/docs/Web/API/Notification/Notification\n     * @param {object|string} config Notification config data or simple message string\n     * @returns {Promise<Event>|null} A promise that resolves to the click event or null\n     */\n    notify(config) {\n        if (config.return) return _ui.notification(config)\n\n        _ui.notification(config)\n            .then( (res) => { // eslint-disable-line promise/always-return\n                log('info', 'Uib:notification', 'Notification completed event', res)()\n                // if (config.return) return res\n            })\n            .catch( (err) => {\n                log('error', 'Uib:notification', 'Notification error event', err)()\n            })\n        return null\n    }\n\n    /** Get or create a (hopefully) unique ID\n     * @param {HTMLFormElement} el Source form element\n     * @returns {string|null} A hopefully unique element ID\n     */\n    returnElementId(el) {\n        return el.id !== '' ? el.id : (el.name !== '' ? `${el.name}-${++this.#uniqueElID}` : (el.type ? `${el.type}-${++this.#uniqueElID}` : `${el.localName}-${++this.#uniqueElID}`))\n    }\n\n    /** Scroll the page\n     * https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView\n     * @param {string} [cssSelector] Optional. If not set, scrolls to top of page.\n     * @param {{block:(string|undefined),inline:(string|undefined),behavior:(string|undefined)}} [opts] Optional. DOM scrollIntoView options\n     * @returns {boolean} True if element was found, false otherwise\n     */\n    scrollTo(cssSelector, opts) {\n        // @ts-ignore\n        if (!opts) opts = {}\n        if (!cssSelector || cssSelector === 'top'  || cssSelector === 'start') cssSelector = 'body'\n        else if (cssSelector === 'bottom' || cssSelector === 'end') {\n            cssSelector = 'body'\n            opts.block = 'end'\n        }\n        const el = this.$(cssSelector)\n        if (el) {\n            el.scrollIntoView(opts)\n            return true\n        }\n        return false\n    }\n\n    /** Show/hide a display card on the end of the visible HTML that will dynamically display the last incoming msg from Node-RED\n     * The card has the id `uib_last_msg`. Updates are done from a listener set up in the start function.\n     * @param {boolean|undefined} showHide true=show, false=hide. undefined=toggle.\n     * @param {string|undefined} parent Optional. If not undefined, a CSS selector to attach the display to. Defaults to `body`\n     * @returns {boolean} New state\n     */\n    showMsg(showHide, parent = 'body') {\n        if ( showHide === undefined ) showHide = !this.#isShowMsg\n        this.#isShowMsg = showHide\n        let slot = 'Waiting for a message from Node-RED'\n\n        if (this.msg && Object.keys(this.msg).length > 0) {\n            slot = this.syntaxHighlight(this.msg)\n        }\n\n        if ( showHide === false ) {\n            _ui._uiRemove( {\n                components: [\n                    '#uib_last_msg_wrap',\n                ],\n            })\n        } else {\n            _ui._uiReplace({\n                components: [\n                    {\n                        type: 'div',\n                        id: 'uib_last_msg_wrap',\n                        parent: parent,\n                        attributes: {\n                            title: 'Last message from Node-RED',\n                        },\n                        components: [\n                            {\n                                type: 'button',\n                                attributes: {\n                                    onclick: 'uibuilder.copyToClipboard(\"msg\")',\n                                    class: 'compact',\n                                    style: 'right:3em;',\n                                    title: 'Copy message to clipboard',\n                                },\n                                slot: '\uD83D\uDCCB',\n                            },\n                            {\n                                type: 'button',\n                                attributes: {\n                                    onclick: 'uibuilder.showMsg()',\n                                    class: 'compact',\n                                    style: 'right:.5em;',\n                                    title: 'Turn off message display',\n                                },\n                                slot: '\u26D4',\n                            },\n                            {\n                                type: 'pre',\n                                id: 'uib_last_msg',\n                                // parent: 'uib_last_msg_wrap',\n                                attributes: {\n                                    class: 'syntax-highlight',\n                                },\n                                slot: slot,\n                            },\n                        ],\n                    },\n                ],\n            })\n        }\n\n        return showHide\n    }\n\n    /** Show/hide a display card on the end of the visible HTML that will dynamically display the current status of the uibuilder client\n     * The card has the id `uib_status`.\n     * The display is updated by an event listener created in the class constructor.\n     * @param {boolean|undefined} showHide true=show, false=hide. undefined=toggle.\n     * @param {string|undefined} parent Optional. If not undefined, a CSS selector to attach the display to. Defaults to `body`\n     * @returns {boolean} New state\n     */\n    showStatus(showHide, parent = 'body') {\n        if ( showHide === undefined ) showHide = !this.#isShowStatus\n        this.#isShowStatus = showHide\n\n        if ( showHide === false ) {\n            _ui._uiRemove( {\n                components: [\n                    '#uib_status',\n                ],\n            })\n            return showHide\n        }\n\n        const root = {\n            components: [\n                {\n                    type: 'div',\n                    id: 'uib_status',\n                    parent: parent,\n                    attributes: {\n                        title: 'Current status of the uibuilder client',\n                        class: 'text-smaller',\n                    },\n                    components: [\n                        {\n                            type: 'table',\n                            components: [\n                                {\n                                    type: 'tbody',\n                                    components: [],\n                                }\n                            ],\n                        }\n                    ],\n                }\n            ],\n        }\n        const details = root.components[0].components[0].components[0].components\n\n        Object.values(this.#showStatus).forEach( (entry) => {\n            details.push({\n                type: 'tr',\n                attributes: {\n                    title: entry.description,\n                },\n                components: [\n                    {\n                        type: 'th',\n                        slot: entry.label,\n                    },\n                    {\n                        type: 'td',\n                        attributes: {\n                            'data-varType': entry.var,\n                        },\n                        slot: entry.var === 'version' ? Uib._meta.version : JSON.stringify(this[entry.var]),\n                    }\n                ],\n            })\n        })\n\n        _ui._uiReplace(root)\n\n        return showHide\n    }\n\n    /** Use the Mutation Observer browser API to watch for changes to a single element on the page.\n     * OMG! It is sooo hard to turn the data into something that successfully serialises so it can be sent back to Node-RED!\n     * NB: Each cssSelector creates a unique watcher. Sending the same selector overwrites the previous one.\n     * @param {string} cssSelector A CSS Selector that selects the element to watch for changes\n     * @param {boolean|\"toggle\"} [startStop] true=start watching the DOM, false=stop. Default='toggle'\n     * @param {boolean} [send] true=Send changes to Node-RED, false=Don't send. Default=true\n     * @param {boolean} [showLog] true=Output changes to log, false=stop. Default=true. Log level is 2 (Info)\n     * @returns {boolean} True if the watch is on, false otherwise\n     */\n    uiWatch(cssSelector, startStop = 'toggle', send = true, showLog = true) {\n        // Select the node that will be observed for mutations\n        const targetNode = document.querySelector(cssSelector)\n        if (!targetNode) {\n            log('warn', 'uibuilder.module.js:uiWatch', `CSS Selector '${cssSelector}' not found.`)()\n            return false\n        }\n\n        if (startStop === 'toggle' || startStop === undefined || startStop === null) {\n            if (this.#uiObservers[cssSelector]) startStop = false\n            else startStop = true\n        }\n\n        // Need a ref to the Uib this\n        const that = this\n\n        if (startStop === true) {\n            // Create an observer instance\n            this.#uiObservers[cssSelector] = new MutationObserver( function( mutationList /* , observer */ ) {\n                const out = []\n\n                mutationList.forEach( (mu) => {\n                    // console.log({ mu })\n                    const oMu = {\n                        type: mu.type,\n                        oldValue: mu.oldValue !== null ? mu.oldValue : undefined,\n                    }\n\n                    if (mu.addedNodes.length > 0) {\n                        oMu.addedNodes = []\n                        mu.addedNodes.forEach( (an, i) => {\n                            oMu.addedNodes.push(_ui.nodeGet(mu.addedNodes[i]))\n                        })\n                    }\n\n                    if (mu.removedNodes.length > 0) {\n                        oMu.removedNodes = []\n                        mu.removedNodes.forEach( (an, i) => {\n                            oMu.removedNodes.push(_ui.nodeGet(mu.removedNodes[i]))\n                        })\n                    }\n\n                    if ( mu.type === 'attributes' ) {\n                        oMu.attributeName = mu.attributeName\n                        // @ts-ignore\n                        oMu.newValue = mu.target.attributes[mu.attributeName].value\n                    }\n\n                    out.push(oMu)\n                })\n\n                // Custom event\n                that._dispatchCustomEvent('uibuilder:domChange', out)\n                // Send a msg back to node-red\n                if (send === true) {\n                    that.send({\n                        _ui: {\n                            cssSelector: cssSelector,\n                            uiChanges: out,\n                        },\n                        topic: that.topic || `DOM Changes for '${cssSelector}'`,\n                    })\n                }\n                // Log to info\n                if (showLog === true) {\n                    log('info', 'uibuilder.module.js:uiWatch', `DOM Changes for '${cssSelector}'`, { uiChanges: out, }, { mutationList, })()\n                }\n            } )\n\n            // Start observing the target node for configured mutations\n            this.#uiObservers[cssSelector].observe(targetNode, { attributes: true, childList: true, subtree: true, characterData: true, })\n            log('trace', 'uibuilder.module.js:uiWatch', `Started Watching DOM changes for '${cssSelector}'`)()\n        } else {\n            this.#uiObservers[cssSelector].disconnect()\n            delete this.#uiObservers[cssSelector]\n            log('trace', 'uibuilder.module.js:uiWatch', `Stopped Watching DOM changes for '${cssSelector}'`)()\n        }\n\n        return startStop\n    } // ---- End of watchDom ---- //\n\n    /** Use the Mutation Observer browser API to watch for and save changes to the HTML\n     * Once the observer is created, it will be reused.\n     * Sending true or undefined will turn on the observer, false turns it off.\n     * saveHtmlCache is called whenever anything changes in the dom. This allows\n     * users to call restoreHtmlFromCache() on page load if desired to completely reload\n     * to the last saved state.\n     * @param {boolean} startStop true=start watching the DOM, false=stop\n     */\n    watchDom(startStop) {\n        // Select the node that will be observed for mutations\n        const targetNode = document.documentElement\n\n        // Need a ref to the Uib this\n        const that = this\n\n        // Create an observer instance\n        if (!this._htmlObserver) {\n            this._htmlObserver = new MutationObserver( function(/* mutationList, observer */) {\n                // We don't need to know the details - so kill off any outstanding mutation records\n                this.takeRecords()\n                // Save the updated entire HTML in localStorage\n                that.saveHtmlCache()\n            } )\n        }\n\n        if (startStop === true || startStop === undefined) {\n            // Start observing the target node for configured mutations\n            this._htmlObserver.observe(targetNode, { attributes: true, childList: true, subtree: true, characterData: true, })\n            log('trace', 'uibuilder.module.js:watchDom', 'Started Watching and saving DOM changes')()\n        } else {\n            this._htmlObserver.disconnect()\n            log('trace', 'uibuilder.module.js:watchDom', 'Stopped Watching and saving DOM changes')()\n        }\n    } // ---- End of watchDom ---- //\n\n    // #endregion -------- -------- -------- //\n\n    // #region ------- HTML cache --------- //\n\n    /** Clear the saved DOM from localStorage */\n    clearHtmlCache() {\n        this.removeStore('htmlCache')\n        log('trace', 'uibuilder.module.js:clearHtmlCache', 'HTML cache cleared')()\n    }\n\n    /** Restore the complete DOM (the whole web page) from browser localStorage if available */\n    restoreHtmlFromCache() {\n        // Is the html cached? If so, restore it\n        const htmlCache = this.getStore('htmlCache')\n        if (htmlCache) {\n            const targetNode = document.getElementsByTagName('html')[0]\n            // Restore the entire HTML\n            targetNode.innerHTML = htmlCache\n            log('trace', 'uibuilder.module.js:restoreHtmlFromCache', 'Restored HTML from cache')()\n        } else {\n            log('trace', 'uibuilder.module.js:restoreHtmlFromCache', 'No cache to restore')()\n        }\n    }\n\n    /** Save the current DOM state to browser localStorage.\n     * localStorage is persistent and so can be recovered even after a browser restart.\n     */\n    saveHtmlCache() {\n        // Save the updated entire HTML in localStorage\n        this.setStore('htmlCache', document.documentElement.innerHTML)\n    }\n\n    // #endregion -------- -------- -------- //\n\n    // #region ------- Message Handling (To/From Node-RED) -------- //\n\n    /** Handles original control msgs (not to be confused with \"new\" msg._uib controls)\n     * @param {*} receivedCtrlMsg The msg received on the socket.io control channel\n     * @private\n     */\n    _ctrlMsgFromServer(receivedCtrlMsg) {\n        this._dispatchCustomEvent('uibuilder:ctrlMsgReceived', receivedCtrlMsg)\n        this.set('serverShutdown', false) // obviously, since we got a msg from the server, it can't be shutdown. This is reset to true if we get a shutdown msg.\n\n        // track received high-res timestamp\n        const ts = performance.now()\n\n        // Make sure that msg is an object & not null\n        if (receivedCtrlMsg === null) {\n            receivedCtrlMsg = {}\n        } else if (typeof receivedCtrlMsg !== 'object') {\n            const msg = {}\n            msg['uibuilderCtrl:' + this._ioChannels.control] = receivedCtrlMsg\n            receivedCtrlMsg = msg\n        }\n\n        // Add high-res timestamp to msg\n        receivedCtrlMsg._receivedHRtime = ts\n\n        // @since 2018-10-07 v1.0.9: Work out local time offset from server\n        this._checkTimestamp(receivedCtrlMsg)\n\n        this.set('ctrlMsg', receivedCtrlMsg)\n        this.set('msgsCtrlReceived', ++this.msgsCtrlReceived)\n\n        log('trace', 'Uib:ioSetup:_ctrlMsgFromServer', `Channel '${this._ioChannels.control}'. Received control msg #${this.msgsCtrlReceived}`, receivedCtrlMsg)()\n\n        /** Process control msg types */\n        switch (receivedCtrlMsg.uibuilderCtrl) {\n            // Node-RED is shutting down\n            case 'shutdown': {\n                this.set('serverShutdown', true)\n                // Turn off socket.io auto-reconnect for 30 seconds to allow Node-RED to restart without the client trying to reconnect to the old server\n                this.disconnect('\u274C Received \"shutdown\" from server')\n                setTimeout( () => {\n                    this.connect('Re-enabled socket.io auto-reconnect after shutdown')\n                }, 30000)\n                break\n            }\n\n            /** We are connected to the server - 1st msg from server */\n            case 'client connect': {\n                log('trace', `Uib:ioSetup:${this._ioChannels.control}`, 'Received \"client connect\" from server', receivedCtrlMsg)()\n                log('info', `Uib:ioSetup:${this._ioChannels.control}`, `\u2705 Server connected. Version: ${receivedCtrlMsg.version}\\nServer time: ${receivedCtrlMsg.serverTimestamp}, Sever time offset: ${this.serverTimeOffset} hours. Max msg size: ${receivedCtrlMsg.maxHttpBufferSize}`)()\n\n                if ( !Uib._meta.version.startsWith(receivedCtrlMsg.version.split('-')[0]) ) {\n                    log('warn', `Uib:ioSetup:${this._ioChannels.control}`, `Server version (${receivedCtrlMsg.version}) not the same as the client version (${Uib._meta.version})`)()\n                }\n\n                if (this.autoSendReady === true) {\n                    log('trace', `Uib:ioSetup:${this._ioChannels.control}/client connect`, 'Auto-sending ready-for-content/replay msg to server')\n                    // @since 0.4.8c Add cacheControl property for use with node-red-contrib-infocache\n                    // @since 6.1.0 Don't bother, we use the \"client connect\" msg\n                    // this._send({\n                    //     'uibuilderCtrl': 'ready for content',\n                    //     'cacheControl': 'REPLAY',\n                    // }, this._ioChannels.control)\n                }\n\n                // Save the current server max msg size - defaults to 1mb, change in settings.js\n                this.maxHttpBufferSize = receivedCtrlMsg.maxHttpBufferSize\n\n                break\n            }\n\n            // We requested this page's metadata from the server using getPageMeta() - this handles the response\n            case 'get page meta': {\n                this.set('pageMeta', receivedCtrlMsg.payload)\n                break\n            }\n\n            default: {\n                log('trace', `uibuilder:ioSetup:${this._ioChannels.control}`, `Received ${receivedCtrlMsg.uibuilderCtrl} from server`)\n                // Anything else to do for other control msgs?\n            }\n        } // ---- End of process control msg types ---- //\n    } // -- End of websocket receive CONTROL msg from Node-RED -- //\n\n    /** Do we want to process something? Check pageName, clientId, tabId. Defaults to yes.\n     * @param {*} obj Either a msg._ui or msg._uib object to check\n     * @returns {boolean} True if we should process the inbound _ui/_uib msg, false if not.\n     * @private\n     */\n    _forThis(obj) {\n        let r = true\n\n        // Is this msg for this pageName?\n        if (obj.pageName && obj.pageName !== this.pageName) {\n            log('trace', 'Uib:_msgRcvdEvents:_forThis', 'Not for this page')()\n            r = false\n        }\n\n        // Is this msg for this clientId?\n        if (obj.clientId && obj.clientId !== this.clientId) {\n            log('trace', 'Uib:_msgRcvdEvents:_forThis', 'Not for this clientId')()\n            r = false\n        }\n\n        // Is this msg for this tabId?\n        if (obj.tabId && obj.tabId !== this.tabId) {\n            log('trace', 'Uib:_msgRcvdEvents:_forThis', 'Not for this tabId')()\n            r = false\n        }\n\n        return r\n    }\n\n    /** Handle received messages - Process some msgs internally, emit specific events on document that make it easy for coders to use\n     * @param {object} msg The message received from Node-RED\n     * @private\n     */\n    _msgRcvdEvents(msg) {\n        // Message received\n        this._dispatchCustomEvent('uibuilder:stdMsgReceived', msg)\n\n        // Topic\n        if ( msg.topic ) this._dispatchCustomEvent(`uibuilder:msg:topic:${msg.topic}`, msg)\n\n        // Check whether the msg has already been processed - if so, we don't need to process again\n        if (msg._uib_processed_by) return\n        msg._uib_processed_by = '_msgRcvdEvents'\n\n        // Handle msg._uib special requests\n        if (msg._uib) {\n            // Don't process if the inbound msg is not for us\n            if (!this._forThis(msg._uib)) return\n\n            /** Process a client reload request from Node-RED - as the page is reloaded, everything else is ignored\n             * Note that msg._ui.reload is also actioned via the _ui processing below\n             */\n            if (msg._uib.reload === true) {\n                log('trace', 'Uib:_msgRcvdEvents:_uib:reload', 'reloading')()\n                msg._uib_processed_by = '_msgRcvdEvents - reload'\n                location.reload()\n                return\n            }\n\n            // Process msg._uib.command messages - allows Node-RED to run uibuilder FE functions\n            if (msg._uib.command) {\n                msg._uib_processed_by = '_msgRcvdEvents - remote command'\n                this._uibCommand(msg)\n                return\n            }\n\n            // Better to request via msg._ui - these are for backwards compatibility\n            if ( msg._uib.componentRef === 'globalNotification' ) {\n                msg._uib_processed_by = '_msgRcvdEvents - globalNotification'\n                _ui.showDialog('notify', msg._uib.options, msg)\n            }\n            if ( msg._uib.componentRef === 'globalAlert' ) {\n                msg._uib_processed_by = '_msgRcvdEvents - globalAlert'\n                _ui.showDialog('alert', msg._uib.options, msg)\n            }\n        }\n\n        // Handle msg._ui requests\n        if ( msg._ui ) {\n            // Don't process if the inbound msg is not for us\n            if (!this._forThis(msg._ui)) return\n\n            log('trace', 'Uib:_msgRcvdEvents:_ui', 'Calling _uiManager')()\n            msg._uib_processed_by = '_msgRcvdEvents - _ui'\n            this._dispatchCustomEvent('uibuilder:msg:_ui', msg)\n            _ui._uiManager(msg)\n        }\n    }\n\n    /** Internal send fn. Send a standard or control msg back to Node-RED via Socket.IO\n     * NR will generally expect the msg to contain a payload topic\n     * @param {object} msgToSend The msg object to send.\n     * @param {string} [channel] The Socket.IO channel to use, must be in self.ioChannels or it will be ignored. Default=uiBuilderClient\n     * @param {string} [originator] A Node-RED node ID to return the message to. Default=''\n     * @private\n     */\n    _send(msgToSend, channel, originator = '') {\n        if (channel === null || channel === undefined) channel = this._ioChannels.client\n\n        // Make sure msgToSend is an object & add props to control msgs\n        if (channel === this._ioChannels.client) {\n            msgToSend = this.makeMeAnObject(msgToSend, 'payload')\n            if (this.hasUibRouter()) {\n                if (!msgToSend._uib) msgToSend._uib = {}\n                msgToSend._uib.routeId = this.uibrouter_CurrentRoute\n            }\n        } else if (channel === this._ioChannels.control) {\n            msgToSend = this.makeMeAnObject(msgToSend, 'uibuilderCtrl')\n            if (!Object.prototype.hasOwnProperty.call(msgToSend, 'uibuilderCtrl')) {\n                msgToSend.uibuilderCtrl = 'manual send'\n            }\n            // help remember where this came from as ctrl msgs can come from server or client\n            msgToSend.from = 'client'\n            // Add current route id if needed\n            if (this.hasUibRouter()) msgToSend.routeId = this.uibrouter_CurrentRoute\n        }\n\n        /** since 2020-01-02 Added _socketId which should be the same as the _socketId on the server */\n        msgToSend._socketId = this._socket.id\n\n        // WARNING: You cannot change any of the this._socket.auth settings at this point\n\n        // Add the originator metadata if required\n        if (originator === '' && this.originator !== '') originator = this.originator\n        if (originator !== '') Object.assign(msgToSend, { _uib: { originator: originator, }, })\n\n        // If the msg does not have a topic - see if we want to add one\n        if ( !Object.prototype.hasOwnProperty.call(msgToSend, 'topic') ) {\n            // From the default (`uibuilder.set('topic', 'some topic')`)\n            if (this.topic !== undefined && this.topic !== '') msgToSend.topic = this.topic\n            else {\n                // Did the last inbound msg have a topic?\n                if ( Object.prototype.hasOwnProperty.call(this, 'msg') && this.msg !== null && Object.prototype.hasOwnProperty.call(this.msg, 'topic') ) {\n                    msgToSend.topic = this.msg.topic\n                }\n            }\n        }\n\n        // If a standard send & _ui property exists, make sure to add _ui.from = 'client' & routerId if needed\n        if (msgToSend._ui) {\n            msgToSend._ui.from = 'client'\n            if (this.hasUibRouter()) msgToSend._ui.routeId = this.uibrouter_CurrentRoute\n        }\n\n        // Check size and warn if may be too large - doesn't work if obj contains a buffer\n        // const approxMsgSize = this.getObjectSize(msgToSend)\n        // console.log(approxMsgSize, this.maxHttpBufferSize, approxMsgSize >= this.maxHttpBufferSize, msgToSend, this.getObjectSize(msgToSend))\n        // if (approxMsgSize >= this.maxHttpBufferSize) {\n        //     log('error', 'Uib:_send', `Message may be too large to send. Approx msg size: ${approxMsgSize}. Max msg size: ${this.maxHttpBufferSize}`)()\n        // }\n\n        // Track how many messages have been sent & last msg sent\n        let numMsgs\n        if (channel === this._ioChannels.client) {\n            this.set('sentMsg', msgToSend)\n            numMsgs = this.set('msgsSent', ++this.msgsSent)\n        } else if (channel === this._ioChannels.control) {\n            this.set('sentCtrlMsg', msgToSend)\n            numMsgs = this.set('msgsSentCtrl', ++this.msgsSentCtrl)\n        }\n        log('trace', 'Uib:_send', ` Channel '${channel}'. Sending msg #${numMsgs}`, msgToSend)()\n\n        this._socket.emit(channel, msgToSend)\n    } // --- End of Send Msg Fn --- //\n\n    /** Callback handler for messages from Node-RED\n     * NOTE: `this` is the class here rather the `socket` as would be normal since we bind the correct `this` in the call.\n     *       Use this._socket if needing reference to the socket.\n     * @callback ioSetupFromServer Called from ioSetup/this._socket.on(this.#ioChannels.server, this.stdMsgFromServer.bind(this))\n     * @param {object} receivedMsg The msg object from Node-RED\n     * @this Uib\n     * @private\n     */\n    _stdMsgFromServer(receivedMsg) {\n        // track received high-res timestamp\n        const ts = performance.now()\n\n        // Make sure that msg is an object & not null\n        receivedMsg = this.makeMeAnObject(receivedMsg, 'payload')\n\n        // Add high-res timestamp to msg\n        receivedMsg._receivedHRtime = ts\n\n        // Don't process if the inbound msg is not for us\n        if (receivedMsg._uib && !this._forThis(receivedMsg._uib)) return\n        if (receivedMsg._ui && !this._forThis(receivedMsg._ui)) return\n\n        // @since 2018-10-07 v1.0.9: Work out local time offset from server\n        this._checkTimestamp(receivedMsg)\n\n        // Track how many messages have been received\n        this.set('msgsReceived', ++this.msgsReceived)\n\n        // Emit specific document events on msg receipt that make it easy for coders to use\n        this._msgRcvdEvents(receivedMsg)\n\n        if ( !('_ui' in receivedMsg && !('payload' in receivedMsg)) ) {\n            // Save the msg for further processing\n            this.set('msg', receivedMsg)\n        }\n\n        log('info', 'Uib:ioSetup:stdMsgFromServer', `Channel '${this._ioChannels.server}'. Received msg #${this.msgsReceived}.`, receivedMsg)()\n\n        // ! NOTE: Don't try to handle specialist messages here. See _msgRcvdEvents.\n    } // -- End of websocket receive DATA msg from Node-RED -- //\n\n    /** Process msg._uib.command - Remember to update #extCommands with new allowed commands\n     * @param {object} msg Msg from Node-RED containing a msg._uib object\n     * @private\n     */\n    _uibCommand(msg) {\n        if (!msg._uib || !msg._uib.command) {\n            log('error', 'uibuilder:_uibCommand', 'Invalid command message received', { msg, })()\n            msg.payload = msg.error = 'Invalid command message received'\n            this.send(msg)\n            return\n        }\n        const cmd = msg._uib.command\n        // Disallowed command request outputs error and ignores the msg (NB: Case must match)\n        if (!this.#extCommands.includes(cmd.trim())) {\n            log('error', 'Uib:_uibCommand', `Command '${cmd} is not allowed to be called externally`)()\n            return\n        }\n        // @since v7.5.0 allow msg._uib.options instead of prop/value to allow more flexible commands\n        const prop = msg._uib?.prop\n        const value = msg._uib?.value\n        const quiet = msg._uib?.quiet ?? msg._uib?.options?.quiet ?? false\n        const options = msg._uib?.options ?? { type: prop, title: value, quiet: quiet, }\n        let response, info\n\n        // Don't forget to update `#extCommands`, `docs/client-docs/control-from-node-red.md` & `functions.md`\n        switch (cmd) {\n            // case 'elementIsVisible': { // temporarily deprecated\n            //     response = this.elementIsVisible(prop)\n            //     // info = `Element \"${prop}\" ${response ? 'is visible' : 'is not visible'}`\n            //     break\n            // }\n\n            case 'elementExists': {\n                response = this.elementExists(prop, false)\n                info = `Element \"${prop}\" ${response ? 'exists' : 'does not exist'}`\n                break\n            }\n\n            case 'get': {\n                response = this.get(prop)\n                break\n            }\n\n            case 'getManagedVarList': {\n                if (prop === 'full') response = this.getManagedVarList()\n                else response = Object.values(this.getManagedVarList())\n                break\n            }\n\n            case 'getWatchedVars': {\n                if (prop === 'full') response = this.getWatchedVars()\n                else response = Object.values(this.getWatchedVars())\n                break\n            }\n\n            case 'sendHtml':\n            case 'htmlSend': {\n                response = this.htmlSend('', false)\n                break\n            }\n\n            case 'include': {\n                // include is async\n                response = _ui.include(prop, value)\n                break\n            }\n\n            case 'navigate': {\n                let newUrl\n                if (prop) newUrl = prop\n                else if (value) newUrl = value\n                response = this.navigate(newUrl)\n                break\n            }\n\n            case 'scrollTo': {\n                response = this.scrollTo(prop, value)\n                break\n            }\n\n            case 'set': {\n                let store = false\n                let autoload = false\n                if (msg._uib.options && msg._uib.options.store) {\n                    if (msg._uib.options.store === true) store = true\n                    if (msg._uib.options.autoload === true) autoload = true\n                }\n                response = this.set(prop, value, store, autoload)\n                break\n            }\n\n            case 'showMsg': {\n                response = this.showMsg(value, prop)\n                break\n            }\n\n            case 'showStatus': {\n                response = this.showStatus(value, prop)\n                break\n            }\n\n            case 'showOverlay': {\n                if (msg.payload && !options?.content) options.content = msg.payload\n                response = this.showOverlay(options)\n                break\n            }\n\n            case 'uiGet': {\n                response = _ui.uiGet(prop, value)\n                break\n            }\n\n            case 'uiWatch': {\n                response = this.uiWatch(prop)\n                break\n            }\n\n            case 'watchUrlHash': {\n                response = this.watchUrlHash(prop)\n                break\n            }\n\n            default: { // anything else is rejected\n                log('warning', 'Uib:_uibCommand', `Command '${cmd}' not yet implemented`)()\n                break\n            }\n        }\n\n        if (quiet !== true) {\n            if (response === undefined) {\n                response = `'${prop}' is undefined`\n            }\n            if (Object(response).constructor === Promise) {\n                // response = `'${cmd} ${prop}' submitted. Cmd is async, no response available`\n                response\n                    .then( (/** @type {any} */ data) => {\n                        msg.payload = msg._uib.response = data\n                        msg.info = msg._uib.info = info\n                        if (!msg.topic) msg.topic = this.topic || `uib ${cmd} for '${prop}'`\n                        this.send(msg)\n                        return true\n                    })\n                    .catch( (err) => {\n                        log(0, 'Uib:_uibCommand', 'Error: ', err)()\n                    })\n            } else {\n                msg.payload = msg._uib.response = response\n                msg.info = msg._uib.info = info\n                if (!msg.topic) msg.topic = this.topic || `uib ${cmd} for '${prop}'`\n                this.send(msg)\n            }\n        }\n    } // --- end of _uibCommand ---\n\n    /** Send a message to Node-RED and return a promise that resolves when a matching response is received.\n     * The response must have the same msg.topic and msg._uib.correlationId to match.\n     * @param {object} msg The message to send to Node-RED\n     * @param {object} [options] Options for the async send\n     * @param {number} [options.timeout] Timeout in milliseconds (default: 60000 = 60 seconds)\n     * @param {Function} [options.onSuccess] Optional callback function to call on success. Receives the response msg.\n     * @param {string} [options.originator] Optional Node-RED node ID to return the message to\n     * @returns {Promise<object>} Promise that resolves with the response message or rejects on timeout\n     * @example\n     * // Basic usage\n     * const response = await uibuilder.asyncSend({ topic: 'myTopic', payload: 'Hello' })\n     *\n     * // With options\n     * const response = await uibuilder.asyncSend(\n     *     { topic: 'getData', payload: { id: 123 } },\n     *     { timeout: 30000, onSuccess: (msg) => console.log('Got response:', msg) }\n     * )\n     *\n     * // Using .then()\n     * uibuilder.asyncSend({ topic: 'query', payload: 'test' })\n     *     .then(response => console.log('Response:', response))\n     *     .catch(err => console.error('Failed:', err))\n     */\n    asyncSend(msg, options = {}) {\n        const timeout = options.timeout ?? 60000\n        const onSuccess = options.onSuccess\n        const originator = options.originator ?? ''\n\n        // Ensure msg is an object\n        msg = this.makeMeAnObject(msg, 'payload')\n\n        // Generate a unique correlation ID\n        const correlationId = this.randomUUID()\n\n        // Ensure msg has a topic\n        if (!msg.topic) {\n            msg.topic = this.topic || 'uibuilder/asyncSend'\n        }\n\n        // Add correlation ID to the message\n        if (!msg._uib) msg._uib = {}\n        msg._uib.correlationId = correlationId\n\n        const topic = msg.topic\n\n        return new Promise((resolve, reject) => {\n            // Cleanup function to remove listener and clear timeout\n            const cleanup = (tid, lref) => {\n                if (tid) clearTimeout(tid)\n                if (lref !== undefined) {\n                    this.cancelTopic(topic, lref)\n                }\n            }\n\n            // Set up timeout\n            const timeoutId = setTimeout(() => {\n                cleanup(timeoutId, listenerRef)\n                reject(new Error(`asyncSend timeout after ${timeout}ms for topic \"${topic}\" with correlationId \"${correlationId}\"`))\n            }, timeout)\n\n            // Set up listener for response\n            const listenerRef = this.onTopic(topic, (responseMsg) => {\n                // Check if the correlationId matches\n                if (responseMsg._uib?.correlationId === correlationId) {\n                    cleanup(timeoutId, listenerRef)\n\n                    // Call onSuccess callback if provided\n                    if (typeof onSuccess === 'function') {\n                        try {\n                            onSuccess(responseMsg)\n                        } catch (err) {\n                            log('warn', 'Uib:asyncSend', 'onSuccess callback threw an error', err)()\n                        }\n                    }\n\n                    resolve(responseMsg)\n                }\n                // If correlationId doesn't match, ignore this message (keep waiting)\n            })\n\n            // Send the message\n            log('trace', 'Uib:asyncSend', `Sending async message with topic \"${topic}\" and correlationId \"${correlationId}\"`, msg)()\n            this._send(msg, this._ioChannels.client, originator)\n        })\n    }\n\n    /** Send log text to uibuilder's beacon endpoint (works even if socket.io not connected)\n     * @param {string} txtToSend Text string to send\n     * @param {string|undefined} logLevel Log level to use. If not supplied, will default to debug\n     */\n    beaconLog(txtToSend, logLevel) {\n        if (!logLevel) logLevel = 'debug'\n        navigator.sendBeacon('./_clientLog', `${logLevel}::${txtToSend}`)\n    }\n\n    /** Request the current page's metadata from the server - response is handled automatically in _ctrlMsgFromServer */\n    getPageMeta() {\n        this.sendCtrl({\n            uibuilderCtrl: 'get page meta',\n        })\n    }\n\n    /** Easily send the entire DOM/HTML msg back to Node-RED\n     * @param {string} [originator] A Node-RED node ID to return the message to\n     * @param {boolean} [send] If true (default) directly send response to Node-RED. Is false when calling from Node-RED as a command.\n     * @returns {string} The HTML as a string\n     */\n    htmlSend(originator = '', send = true) {\n        const out = `<!doctype html>\\n${document.documentElement.outerHTML}`\n\n        // Set up the msg to send - NB: Topic may be added by this._send\n        const msg = {\n            payload: out,\n            length: out.length,\n            topic: this.topic,\n        }\n\n        log('trace', 'Uib:htmlSend', 'Sending full HTML to Node-RED', msg)()\n\n        if (send === true) this._send(msg, this._ioChannels.client, originator)\n        return out\n    }\n\n    /** Send log info back to Node-RED over uibuilder's websocket control output (Port #2)\n     * @param {...*} arguments All arguments passed to the function are added to the msg.payload\n     */\n    logToServer() {\n        this.sendCtrl({\n            uibuilderCtrl: 'client log message',\n            payload: arguments,\n            // \"version\":\"6.1.0-iife.min\",\n            _socketId: this._socket.id,\n            // \"ip\":\"::1\",\n            clientId: this.clientId,\n            tabId: this.tabId,\n            // \"url\":\"esp-test\",\n            pageName: this.pageName,\n            connections: this.connectedNum,\n            lastNavType: this.lastNavType,\n        })\n    }\n\n    /** Easily send a msg back to Node-RED on a DOM event\n     * @example In plain HTML/JavaScript\n     *    `<button id=\"button1\" name=\"button 1\" data-fred=\"jim\"></button>`\n     *    $('#button1').onclick = (evt) => {\n     *      uibuilder.eventSend(evt)\n     *    }\n     * @example\n     * In VueJS: `<b-button id=\"myButton1\" @click=\"doEvent\" data-something=\"hello\"></b-button>`\n     * In VueJS methods: `doEvent: uibuilder.eventSend,`\n     *\n     * All `data-` attributes will be passed back to Node-RED,\n     *    use them instead of arguments in the click function.\n     *    All target._ui custom properties are also passed back to Node-RED.\n     *\n     * @param {MouseEvent|any} domevent DOM Event object\n     * @param {string} [originator] A Node-RED node ID to return the message to\n     */\n    eventSend(domevent, originator = '') {\n        // @ts-ignore Handle case where vue messes up `this`\n        if ( this.$attrs ) {\n            log('error', 'Uib:eventSend', '`this` has been usurped by VueJS. Make sure that you wrap the call in a function: `doEvent: function (event) { uibuilder.eventSend(event) },`' )()\n            return\n        }\n        if (!domevent && !event) {\n            log('warn', 'Uib:eventSend', 'Neither the domevent nor the hidden event properties are set. You probably called this function directly rather than applying to an on click event.' )()\n            return\n        }\n        // Handle no argument, e.g. <button onClick=\"uibuilder.eventSend()\"> - event is a hidden variable when fn used in addEventListener\n        if (!domevent || !domevent.constructor) domevent = event\n\n        // The argument must be a DOM event\n        if ((!domevent.constructor.name.endsWith('Event')) || (!domevent.currentTarget)) {\n            log('warn', 'Uib:eventSend', `ARGUMENT NOT A DOM EVENT - use data attributes not function arguments to pass data. Arg Type: ${domevent.constructor.name}`, domevent)()\n            return\n        }\n\n        // Prevent default event action\n        domevent.preventDefault()\n\n        // The target element\n        const target = domevent.currentTarget\n\n        // Get target custom properties - only shows custom props not element default ones\n        const props = this.getElementCustomProps(target)\n\n        // Attempt to get target attributs - can fail for certain target types\n        const attribs = this.getElementAttributes(target)\n\n        // Msg.payload\n        let payload = {}\n\n        // If target is embedded in a form, include ALL the form data in the output\n        let formDetails\n        if ( target.form ) {\n            formDetails = {\n                id: this.returnElementId(target.form),\n                valid: target.form.checkValidity(),\n            }\n\n            Object.values(target.form).forEach( (frmEl, i) => {\n                // Ignore <fieldset>, <object> - they don't have values\n                if (['fieldset', 'object'].includes(frmEl.type)) return\n\n                // NB: If type=files, this also sends the file to Node-RED\n                const details = this.getFormElementDetails(frmEl)\n                if (details) {\n                    // For type=file, get the file details as the value (array as might be multiple files).\n                    // el.files is a FileList type & each entry is a File type - have to process these manually - stupid HTML!\n                    // https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications\n                    if (frmEl.type === 'file' && frmEl.files.length > 0) {\n                        // Walk through each file in the FileList, get the details and send the file to Node-RED\n                        // details.value = this._processFilesInput(frmEl.files, frmEl)\n                        details.value = this._processFilesInput(frmEl)\n                    }\n\n                    formDetails[details.id] = details\n                    // simplified for addition to msg.payload\n                    payload[details.id] = details.value\n                }\n            })\n        } else {\n            if (target.type === 'file') {\n                // Walk through each file in the FileList, get the details and send the file to Node-RED\n                // payload = this._processFilesInput(target.files, {id: target?.id, name: target?.name,})\n                payload = this._processFilesInput(target)\n            }\n        }\n\n        // Check for CSS Classes\n        const classes = this.getElementClasses(target)\n\n        // Each `data-xxxx` attribute is added as a property\n        if (Object.keys(target.dataset).length > 0) payload = { ...payload, ...target.dataset, }\n\n        // Check for element value/check props\n        const { value, checked, } = this.getFormElementValue(target)\n        if (value !== null) payload.value = value\n        if (checked !== null) payload.checked = checked\n\n        // Handle Notification events\n        let nprops\n        if ( Object.prototype.toString.call(target) === '[object Notification]') {\n            // Fixed payload for convenience\n            payload = `notification-${target.userAction}`\n            // Capture the notification properties\n            nprops = {\n                // userAction: target.userAction, // uib custom prop: click, close or error\n                actions: target.actions,\n                badge: target.badge,\n                body: target.body,\n                data: target.data,\n                dir: target.dir,\n                icon: target.icon,\n                image: target.image,\n                lang: target.lang,\n                renotify: target.renotify,\n                requireInteraction: target.requireInteraction,\n                silent: target.silent,\n                tag: target.tag,\n                timestamp: target.timestamp,\n                title: target.title,\n                vibrate: target.vibrate,\n            }\n        }\n\n        // Set up the msg to send - NB: Topic may be added by this._send\n        const msg = {\n            // - this may be an empty Object if no data attributes defined\n            payload: payload,\n\n            _ui: {\n                type: 'eventSend',\n                id: target.id !== '' ? target.id : undefined,\n                name: target.name !== '' ? target.name : undefined,\n                slotText: target.textContent ? target.textContent.substring(0, 255) : undefined,\n                dataset: { ...target.dataset, },\n\n                form: formDetails,\n                props: props,\n                attribs: attribs,\n                classes: classes,\n\n                notification: nprops,\n\n                event: domevent.type,\n                altKey: domevent.altKey,\n                ctrlKey: domevent.ctrlKey,\n                shiftKey: domevent.shiftKey,\n                metaKey: domevent.metaKey,\n\n                pointerType: domevent.pointerType,\n                nodeName: target.nodeName,\n\n                clientId: this.clientId,\n                pageName: this.pageName,\n                tabId: this.tabId,\n            },\n        }\n\n        log('trace', 'Uib:eventSend', 'Sending msg to Node-RED', msg)()\n\n        this._send(msg, this._ioChannels.client, originator)\n    }\n\n    /** Send a standard message to NR\n     * @example uibuilder.send({payload:'Hello'})\n     * @param {object} msg Message to send\n     * @param {string} [originator] A Node-RED node ID to return the message to\n     */\n    send(msg, originator = '') {\n        this._send(msg, this._ioChannels.client, originator)\n    }\n\n    // ! TODO: Rooms do not auto-reconnect. Add tracking and update _onConnect\n    // ! TODO: Add receipt handler on joining a room.\n\n    // NOTE: Rooms only understood by server not client so we have to use custom emits\n    //       They do not auto-reconnect\n\n    /** Send a msg to a pre-defined Socket.IO room\n     * @see https://socket.io/docs/v4/rooms/\n     * @param {string} room Name of a Socket.IO pre-defined room.\n     * @param {*} msg Message to send\n     */\n    sendRoom(room, msg) {\n        this._socket.emit('uib-room-send', room, msg )\n    }\n\n    joinRoom(room) {\n        this._socket.emit('uib-room-join', room)\n    }\n\n    leaveRoom(room) {\n        this._socket.emit('uib-room-leave', room)\n    }\n\n    /** Send a control msg to NR\n     * @param {object} msg Message to send\n     */\n    sendCtrl(msg) {\n        this._send(msg, this._ioChannels.control)\n    }\n\n    /**\n     * Send a message to Node-RED on a custom channel - use for UIBUILDER 3rd-party custom nodes\n     * @param {string} channel The custom channel name to use\n     * @param {object} msg The message to send\n     */\n    sendCustom(channel, msg) {\n        this._socket.emit(channel, msg)\n    }\n\n    /** Upload a file to Node-RED over Socket.IO\n     * https://developer.mozilla.org/en-US/docs/Web/API/FileReader\n     * @param {File} file Reference to File API object to upload\n     * @param {object} [meta] Optiona. Additional metadata to send with the file\n     */\n    uploadFile(file, meta) { // srcElIds, seq, seqCount\n        // Create a new FileReader instance\n        const reader = new FileReader()\n\n        // Define the onload event for the FileReader\n        reader.onload = (e) => {\n            // Get the binary content of the file\n            const arrayBuffer = e.target.result\n\n            // Send the binary content to the server along with helpful metadata\n            const msg = {\n                topic: this.topic || 'file-upload',\n                payload: arrayBuffer,\n\n                fileName: file.name,\n                type: file.type,\n                lastModified: file.lastModifiedDate,\n                size: file.size,\n\n                clientId: this.clientId,\n                pageName: this.pageName,\n                tabId: this.tabId,\n\n                ...meta,\n            }\n\n            // Only send if content not too large\n            const maxSize = this.maxHttpBufferSize - 500\n            if (arrayBuffer.byteLength >= maxSize) {\n                msg.payload = undefined\n                msg.error = `File is too large to send. File size: ${arrayBuffer.byteLength}. Max msg size: ${maxSize}`\n                log('error', 'Uib:uploadFile', msg.error)()\n            }\n\n            this.send(msg)\n        }\n\n        // Read the file as an ArrayBuffer\n        reader.readAsArrayBuffer(file)\n    }\n    // #endregion -------- ------------ -------- //\n\n    // #region ------- Web Worker -------- //\n    /** Get HTTP headers that were sent with the page request\n     * Uses a web worker to fetch headers from the server.\n     * @param {string} [headerName] Optional specific header name to retrieve (case-insensitive)\n     * @returns {Promise<object|string|null>} Promise resolving to all headers object, a specific header value, or null\n     * @example\n     * // Get all headers\n     * const allHeaders = await uibuilder.headers()\n     * console.log(allHeaders)\n     *\n     * // Get a specific header\n     * const contentType = await uibuilder.headers('content-type')\n     * console.log(contentType)\n     *\n     * // Using .then()\n     * uibuilder.headers('x-uibuilder-namespace').then(ns => console.log(ns))\n     */\n    // async headers(headerName) {\n    //     return this.#headerWorker.getHeadersAsync(headerName)\n    // }\n\n    /** Get HTTP headers synchronously (may be empty if not yet fetched)\n     * @param {string} [headerName] Optional specific header name to retrieve (case-insensitive)\n     * @returns {object|string|null} All headers object, a specific header value, or null\n     * @example\n     * // Get all headers (may be empty if called too early)\n     * const allHeaders = uibuilder.headersSync()\n     *\n     * // Check if headers are ready first\n     * if (uibuilder.headersReady) {\n     *     const contentType = uibuilder.headersSync('content-type')\n     * }\n     */\n    // headersSync(headerName) {\n    //     return this.#headerWorker.getHeaders(headerName)\n    // }\n\n    /** Check if HTTP headers have been fetched and are available\n     * @returns {boolean} True if headers are ready to be read\n     */\n    // get headersReady() {\n    //     return this.#headerWorker.isReady\n    // }\n\n    /** Re-fetch HTTP headers from the server\n     * Useful if you need to refresh headers after some server-side change\n     * @param {string} [url] Optional URL to fetch headers from (defaults to current page)\n     */\n    // refreshHeaders(url) {\n    //     this.#headerWorker.fetchHeaders(url)\n    // }\n    // #endregion ------- ------- -------- //\n\n    // #region ------- Socket.IO -------- //\n\n    /** Return the Socket.IO namespace\n     * The cookie method is the most reliable but this falls back to trying to work it\n     * out from the URL if cookies not available. That won't work if page is in a sub-folder.\n     * since 2017-10-21 Improve method to cope with more complex paths - thanks to Steve Rickus @shrickus\n     * since 2017-11-10 v1.0.1 Check cookie first then url. cookie works even if the path is more complex (e.g. sub-folder)\n     * since 2020-01-25 Removed httpRoot from namespace to prevent proxy induced errors\n     * @returns {string} Socket.IO namespace\n     * @private\n     */\n    _getIOnamespace() {\n        let ioNamespace\n\n        /** Try getting the namespace cookie. */\n        ioNamespace = this.httpHeaders['uibuilder-namespace'] || this.cookies['uibuilder-namespace']\n        if (ioNamespace.startsWith('/')) ioNamespace = ioNamespace.slice(1)\n\n        // if it wasn't available, try using the current url path\n        if (ioNamespace === undefined || ioNamespace === '') {\n            // split url path & eliminate any blank elements, and trailing or double slashes\n            const u = window.location.pathname.split('/')\n                .filter(function (t) { return t.trim() !== '' })\n\n            /** since v2.0.5 Extra check for 0 length, Issue #73. since 2017-11-06 If the last element of the path is an .html file name, remove it */\n            if (u.length > 0 && (u[u.length - 1].endsWith('.html'))) u.pop()\n\n            // Get the last part of the url path, this MUST match the namespace in uibuilder\n            ioNamespace = u.pop()\n\n            log('trace', 'uibuilder.module.js:getIOnamespace', `Socket.IO namespace found via url path: ${ioNamespace}`)()\n        } else {\n            log('trace', 'uibuilder.module.js:getIOnamespace', `Socket.IO namespace found via cookie: ${ioNamespace}`)()\n        }\n\n        this.url = ioNamespace\n        // Namespace HAS to start with a /\n        ioNamespace = '/' + ioNamespace\n\n        log('trace', 'uibuilder.module.js:getIOnamespace', `Final Socket.IO namespace: ${ioNamespace}`)()\n\n        return ioNamespace\n    } // --- End of set IO namespace --- //\n\n    /** Function used to check whether Socket.IO is connected to the server, reconnect if not (recursive)\n     * @param {number} [delay] Initial delay before checking (ms). Default=2000ms\n     * @param {number} [factor] Multiplication factor for subsequent checks (delay*factor). Default=1.5\n     * @param {number} [depth] Recursion depth\n     * @returns {boolean|undefined} Whether or not Socket.IO is connected to uibuilder in Node-RED\n     * @private\n     */\n    _checkConnect(delay, factor, depth = 1) {\n        if ( navigator.onLine === false ) return // Don't bother if we know we are offline\n\n        if (!delay) delay = this.retryMs\n        if (!factor) factor = this.retryFactor\n\n        log('trace', 'Uib:checkConnect', `Checking connection.\\nConnected: ${this._socket.connected}.\\nTimer: ${this.#timerid}. Depth: ${depth}. Delay: ${delay}. Factor: ${factor}.\\nTransport: ${this.currentTransport}`, this._socket)()\n\n        // If we are connected ...\n        if (this._socket.connected === true) {\n            // Clear the setTimeout\n            if (this.#timerid) {\n                window.clearTimeout(this.#timerid)\n                this.#timerid = null\n            }\n            this.set('ioConnected', true)\n            this.set('socketError', null)\n            return true\n        }\n\n        // ... we aren't connected so:\n        this.set('ioConnected', false)\n\n        // we only want one running at a time\n        if (this.#timerid) window.clearTimeout(this.#timerid)\n\n        // Create the new timer\n        this.#timerid = window.setTimeout(() => {\n            log('warn', 'Uib:checkConnect:setTimeout', `Socket.IO reconnection attempt. Current delay: ${delay}. Depth: ${depth}. Initial Connect: ${this.initialConnect}. Reconnected: ${this.reconnected}`)()\n\n            // this is necessary sometimes when the socket fails to connect on startup\n            this._socket.disconnect()\n\n            // Try to reconnect\n            this._socket.connect()\n\n            // don't need to check whether we have connected as the timer will have been cleared if we have\n            this.#timerid = null\n\n            // @ts-ignore Create new timer for next time round with extended delay\n            this._checkConnect(delay * factor, factor, depth++)\n        }, delay)\n\n        return false\n    } // --- End of checkConnect Fn--- //\n\n    // See message handling section for msg receipt handlers\n\n    /** Called by _ioSetup when Socket.IO connects to Node-RED\n     * @private\n     */\n    _onConnect() {\n        this.currentTransport = this._socket.io.engine.transport.name\n        if (this.initialConnect === null) this.initialConnect = true\n        else this.reconnected++\n\n        // WARNING: You cannot change any of the this._socket.auth settings at this point\n        log(\n            'info',\n            'Uib:ioSetup',\n            `\u2705 SOCKET CONNECTED.\\nConnection count: ${this.connectedNum} (Reconnected: ${this.reconnected}, Initial Connect: ${this.initialConnect}), Is a Recovery?: ${this._socket.recovered}.\\nNamespace: ${this.ioNamespace}\\nTransport: ${this.currentTransport}`\n        )()\n\n        this._dispatchCustomEvent('uibuilder:socket:connected', { Reconnections: this.reconnected, initialConnect: this.initialConnect, numConnections: this.connectedNum, isRecovery: this._socket.recovered, })\n\n        this._socket.io.engine.on('upgrade', () => {\n            this.currentTransport = this._socket.io.engine.transport.name\n            log(\n                'trace',\n                'Uib:_onConnect:onUpgrade',\n                `SOCKET CONNECTION UPGRADED.\\nConnection count: ${this.connectedNum} (Reconnected: ${this.reconnected}, Initial Connect: ${this.initialConnect}), Is a Recovery?: ${this._socket.recovered}.\\nNamespace: ${this.ioNamespace}\\nTransport: ${this.currentTransport}`\n            )()\n        })\n\n        // If, 2 seconds after connection, we don't have an upgrade to websockets, warn the user.\n        setTimeout(() => {\n            if (this.currentTransport !== 'websocket') {\n                log(\n                    'error',\n                    'Uib:Connection',\n                    `Connected to Node-RED but NO SOCKET UPGRADE!\\n\u27A1\uFE0F CHECK NETWORK and any PROXIES for issues. \u2B05\uFE0F\\nConnection count: ${this.connectedNum} (Reconnected: ${this.reconnected}, Initial Connect: ${this.initialConnect}), Is a Recovery?: ${this._socket.recovered}.\\nNamespace: ${this.ioNamespace}\\nTransport: ${this.currentTransport}`\n                )()\n            }\n        }, 2000)\n\n        this._checkConnect() // resets any reconnection timers & sets connected flag\n    }\n\n    /** Called by _ioSetup when Socket.IO disconnects from Node-RED\n     * @param {string} reason Disconnection title\n     * @param {object} details Any details about the disconnection\n     * @private\n     */\n    _onDisconnect(reason, details) {\n        // reason === 'io server disconnect' - redeploy of Node instance\n        // reason === 'transport close' - Node-RED terminating\n        // reason === 'ping timeout' - didn't receive a pong response?\n        log('info', 'Uib:ioSetup:socket-disconnect', `\u26D4 Socket Disconnected. Reason: ${reason}`, details)()\n\n        this._dispatchCustomEvent('uibuilder:socket:disconnected', { reason, details, })\n\n        // Only attempt auto-reconnect if this was NOT a manual disconnect\n        if (this.#manualDisconnect) {\n            this.#manualDisconnect = false\n            return\n        }\n\n        /** A workaround for SIO's failure to reconnect after a disconnection */\n        this._checkConnect()\n    }\n\n    /** Setup Socket.io\n     * since v2.0.0-beta2 Moved to a function and called by the user (uibuilder.start()) so that namespace & path can be passed manually if needed\n     * @returns {boolean} Attaches socket.io manager to self._socket and updates self.ioNamespace & self.ioPath as needed\n     * @private\n     */\n    _ioSetup() {\n        // Just a notification, actual load is done outside the class (see start of file)\n        if (io === undefined) {\n            log('error', 'Uib:ioSetup', 'Socket.IO client not loaded, Node-RED comms will not work')()\n            return false\n        }\n\n        // If socket is already set up, close it and remove all of the listeners\n        if (this._socket) {\n            log('trace', 'Uib:ioSetup', 'Removing listeners in preparation for redoing Socket.IO connections')()\n            if (this.#timerid) {\n                window.clearTimeout(this.#timerid)\n                this.#timerid = null\n            }\n            this._socket.close()\n            this._socket.offAny()\n            this._socket = undefined\n            this.set('ioConnected', false)\n        }\n\n        if (this.headers) {\n            console.log('HTTP Headers: ', this.headersReady, this.headers)\n        }\n\n        // Update the URL path to make sure we have the right one\n        this.socketOptions.path = this.ioPath\n        // console.log('>> ioPath: ', this.ioPath, ' >> ioNamespace: ', this.ioNamespace, this.socketOptions)\n\n        // Create the socket - make sure client uses Socket.IO version from the uibuilder module (using path)\n        log('trace', 'Uib:ioSetup', `About to create IO object. Transports: [${this.socketOptions.transports.join(', ')}]`)()\n        this._socket = io(this.ioNamespace, this.socketOptions)\n        // console.log(this._socket, '>> ioPath: ', this.ioPath, ' >> ioNamespace: ', this.ioNamespace, this.socketOptions)\n\n        this._connectGlobal()\n\n        /** When the socket is connected - set ioConnected flag and reset connect timer  */\n        this._socket.on('connect', this._onConnect.bind(this))\n\n        // RECEIVE a STANDARD, non-control msg from Node-RED server\n        this._socket.on(this._ioChannels.server, this._stdMsgFromServer.bind(this))\n\n        // RECEIVE a CONTROL msg from Node-RED server - see also sendCtrl()\n        this._socket.on(this._ioChannels.control, this._ctrlMsgFromServer.bind(this))\n\n        // When the socket is disconnected ..............\n        this._socket.on('disconnect', this._onDisconnect.bind(this))\n\n        // Socket.io connection error - probably the wrong ioPath - or client is offline\n        this._socket.on('connect_error', (err) => {\n            if ( navigator.onLine === false ) return // Don't bother with an error if we know we are offline\n            if (!err.message.startsWith('xhr poll error')) {\n                log('error', 'Uib:ioSetup:connect_error', `\u274C Socket.IO Connect Error. Reason: ${err.message}`, err)()\n            }\n            this.set('ioConnected', false)\n            this.set('socketError', err)\n            this._dispatchCustomEvent('uibuilder:socket:disconnected', err)\n        })\n\n        // Socket.io error - from the server (socket.use middleware triggered an error response)\n        this._socket.on('error', (err) => {\n            log('error', 'Uib:ioSetup:error', `\u274C Socket.IO Error. Reason: ${err.message}`, err)()\n            this.set('ioConnected', false)\n            this.set('socketError', err)\n            this._dispatchCustomEvent('uibuilder:socket:disconnected', err)\n        })\n\n        this._socket.io.engine.on('connection_error', (err) => {\n            log(\n                'error',\n                'Uib:ioSetup:io:engine:connection_error',\n                err.code, // 3\n                err.message, // \"Bad request\"\n                err.context // { name: 'TRANSPORT_MISMATCH', transport: 'websocket', previousTransport: 'polling' }\n            )()\n        })\n\n        // Ensure we are connected, retry if not\n        this._checkConnect()\n\n        return true\n\n        /* We really don't need these, just for interest\n            self._socket.io.on('packet', function onPacket(data){\n                // we get one of these for each REAL msg (not ping/pong)\n                console.debug('PACKET', data)\n            })\n            self._socket.on('pong', function(latency) {\n                console.debug('SOCKET PONG - Latency: ', latency)\n                //console.dir(self._socket)\n            }) // --- End of socket pong processing ---\n            self._socket.io.on('packet', function(data){\n                // We get one of these for actual messages, not ping/pong\n                console.debug('PACKET', data)\n            })\n            self._socket.on('connect_timeout', function(timeout) {\n                console.debug('SOCKET CONNECT TIMEOUT - Namespace: ' + ioNamespace + ', Timeout: ' + timeout)\n            }) // --- End of socket connect timeout processing ---\n            self._socket.on('reconnect', function(attemptNum) {\n                console.debug('SOCKET RECONNECTED - Namespace: ' + ioNamespace + ', Attempt #: ' + attemptNum)\n            }) // --- End of socket reconnect processing ---\n            self._socket.on('reconnect_attempt', function(attemptNum) {\n                console.debug('SOCKET RECONNECT ATTEMPT - Namespace: ' + ioNamespace + ', Attempt #: ' + attemptNum)\n            }) // --- End of socket reconnect_attempt processing ---\n            self._socket.on('reconnecting', function(attemptNum) {\n                console.debug('SOCKET RECONNECTING - Namespace: ' + ioNamespace + ', Attempt #: ' + attemptNum)\n            }) // --- End of socket reconnecting processing ---\n            self._socket.on('reconnect_error', function(err) {\n                console.debug('SOCKET RECONNECT ERROR - Namespace: ' + ioNamespace + ', Reason: ' + err.message)\n                //console.dir(err)\n            }) // --- End of socket reconnect_error processing ---\n            self._socket.on('reconnect_failed', function() {\n                console.debug('SOCKET RECONNECT FAILED - Namespace: ' + ioNamespace)\n            }) // --- End of socket reconnect_failed processing ---\n            self._socket.on('ping', function() {\n                console.debug('SOCKET PING')\n            }) // --- End of socket ping processing ---\n            self._socket.on('pong', function(latency) {\n                console.debug('SOCKET PONG - Latency: ', latency)\n            }) // --- End of socket pong processing ---\n            */\n    } // ---- End of ioSetup ---- //\n\n    /** Connect to global namespace & create global listener that updates the `globalMsg` var\n     * @private\n     */\n    _connectGlobal() {\n        this._socketGlobal = io('/', this.socketOptions)\n        this._socketGlobal.onAny( (...args) => {\n            this.set('globalMsg', args.slice(0, -1))\n        })\n    }\n\n    /** Manually (re)connect socket.io\n     * @param {string} [reason] Optional reason text for manual connection, used for logging\n     */\n    connect(reason = 'Manual connect') {\n        this.#manualDisconnect = false\n        log('info', `Uib:connect`, reason)()\n        // Re-enable the Manager's built-in reconnection before connecting\n        this._socket.io.reconnection(true)\n        if (this._socketGlobal) this._socketGlobal.connect()\n        this._socket.connect()\n    }\n\n    /** Manually disconnect socket.io and stop any auto-reconnect timer\n     * @param {string} [reason] Optional reason text for manual disconnection, used for logging\n     */\n    disconnect(reason = 'Manual disconnect') {\n        log('info', `Uib:disconnect`, reason)()\n        // Flag set before disconnecting so that _onDisconnect skips the auto-reconnect workaround\n        this.#manualDisconnect = true\n        // Disable the Manager's built-in reconnection so it doesn't keep polling after disconnect\n        this._socket.io.reconnection(false)\n        // Disconnect both namespaces - _socketGlobal shares the same Manager and will keep it\n        // alive (and polling) if not disconnected alongside _socket\n        if (this._socketGlobal) this._socketGlobal.disconnect()\n        this._socket.disconnect()\n        // As this is a manual disconnect, stop any reconnect timers\n        if (this.#timerid) {\n            window.clearTimeout(this.#timerid)\n            this.#timerid = null\n        }\n    }\n\n    // #endregion -------- ------------ -------- //\n\n    // #region Watch for and process uib-* or data-uib-* attributes in HTML and auto-process\n\n    /** Attempt to load a service worker\n     * https://yonatankra.com/how-service-workers-sped-up-our-website-by-97-5/\n     * @param {string} fileName Name of service worker js file (without .js extension)\n     */\n    // async registerServiceWorker(fileName) {\n    //     if (!navigator.serviceWorker) return\n\n    //     await navigator.serviceWorker.register(\n    //         `./${fileName}.js`,\n    //         {\n    //             scope: './',\n    //         }\n    //     )\n    // }\n\n    /** Wrap an object in a JS proxy\n     * WARNING: Sadly, `let x = uib.createProxy( [1,2] ); x.push(3);` Does not trigger a send because that is classed as a\n     * GET, not a SET.\n     * param {*} target The target object to proxy\n     * returns {Proxy} A proxied version of the target object\n     */\n    // createProxy(target) {\n    //     return new Proxy(target, {\n    //         _doSend(prop, val, oldVal) {\n    //             uibuilder.send({\n    //                 topic: 'uibuilder/proxy/change',\n    //                 _uib: {\n    //                     varChange: {\n    //                         name: self.$name,\n    //                         property: prop,\n    //                         oldValue: oldVal,\n    //                         newValue: val,\n    //                     }\n    //                 },\n    //                 payload: target,\n    //             })\n    //         },\n    //         get(target, prop, receiver) {\n    //             console.log('uib proxy - GET: ', prop, target)\n    //             let val = Reflect.get(...arguments)\n    //             if (typeof val === 'function') val = val.bind(target)\n    //             if (self.$sendChanges) this._doSend(prop, Reflect.get(target))\n    //             return val\n    //         },\n    //         set(target, prop, val, receiver) {\n    //             if (prop === '$sendChanges') {\n    //                 self.$sendChanges = typeof val === 'boolean' ? val : false\n    //                 return true\n    //             }\n    //             if (prop === '$name') {\n    //                 self.$name = typeof val === 'string' ? val : undefined\n    //                 return true\n    //             }\n    //             console.log('uib proxy - SET: ', val, prop, target)\n    //             const oldVal = Reflect.get(...arguments)\n    //             const worked = Reflect.set(target, prop, val, receiver)\n    //             if (self.$sendChanges && worked) {\n    //                 self._doSend(prop, val, oldVal)\n    //             }\n    //             return worked\n    //         },\n    //     })\n    // }\n\n    // #endregion ! EXPERIMENTAL\n\n    // #region ------- Class construction & startup method -------- //\n\n    constructor() {\n        log('trace', 'Uib:constructor', 'Starting')()\n        perf.set('constructor starting', performance.now())\n\n        __uibHeadersPromise.then((headers) => { // eslint-disable-line promise/catch-or-return\n            this.httpHeaders = headers\n            perf.set('http headers', performance.now())\n            // console.log('>> >> HEADERS >> >> ', performance.now(), headers)\n            // trigger a custom event to say that headers are ready\n            this._dispatchCustomEvent('uibuilder:httpHeadersReady', headers)\n            return\n        })\n\n        // Track whether the client is online or offline\n        window.addEventListener('offline', (e) => {\n            this.set('online', false)\n            this.set('ioConnected', false)\n            log('warn', 'Browser', 'DISCONNECTED from network')()\n        })\n        window.addEventListener('online', (e) => {\n            this.set('online', true)\n            log('warn', 'Browser', 'Reconnected to network')()\n            this._checkConnect()\n        })\n\n        /** Tab ID - lasts while the tab is open (even if reloaded)\n         * WARNING: Duplicating a tab retains the same tabId\n         */\n        this.set('tabId', window.sessionStorage.getItem('tabId'))\n        if (!this.tabId) {\n            this.set('tabId', `t${Math.floor(Math.random() * 1000000)}`)\n            window.sessionStorage.setItem('tabId', this.tabId)\n        }\n\n        // document.addEventListener('pagehide', (event) => {\n        //     // console.log(`pagehide. From Cache?: ${event.persisted}`)\n        //     navigator.sendBeacon('./_clientLog', `pagehide. From Cache?: ${event.persisted}`)\n        // })\n        // document.addEventListener('pageshow', (event) => {\n        //     // console.log(`pageshow. From Cache?: ${event.persisted}`)\n        //     navigator.sendBeacon('./_clientLog', `pageshow. From Cache?: ${event.persisted}`)\n        // })\n        document.addEventListener('load', () => {\n            this.set('isVisible', true)\n        })\n        document.addEventListener('visibilitychange', () => {\n            // hidden=unload, minimise. visible=un-minimise (not fired on load)\n            this.set('isVisible', document.visibilityState === 'visible')\n            this.sendCtrl({ uibuilderCtrl: 'visibility', isVisible: this.isVisible, })\n            // navigator.userActivation is experimental Chromium only\n            // console.log('visibilitychange', ':', `Document Event: visibilitychange. Visibility State: ${document.visibilityState}. User Activity- Has:${navigator.userActivation.hasBeenActive}, Is:${navigator.userActivation.isActive}`)\n            // navigator.sendBeacon('./_clientLog', `${(new Date()).toISOString()} Document Event: visibilitychange. Visibility State: ${document.visibilityState}. User Activity- Has:${navigator.userActivation.hasBeenActive}, Is:${navigator.userActivation.isActive}`)\n        })\n\n        // Set a listener to update showStatus table if it is active\n        document.addEventListener('uibuilder:propertyChanged', (event) => {\n            if (!this.#isShowStatus) return\n\n            // @ts-ignore\n            if (event.detail.prop in this.#showStatus) {\n                // @ts-ignore\n                document.querySelector(`td[data-vartype=\"${event.detail.prop}\"]`).innerText = JSON.stringify(event.detail.value)\n            }\n        })\n\n        // Attempt to restore autoload variables\n        try {\n            const autoloadVars = this.getStore('_uibAutoloadVars')\n            if (Object.keys(autoloadVars).length > 0) {\n                Object.keys(autoloadVars).forEach( (id) => {\n                    this.set(id, this.getStore(id))\n                })\n            }\n        } catch (e) {}\n\n        // Watch for URL hash changes in case using a front-end router. Updates watched var `urlHash` and socket.io `auth.urlHash`\n        this._watchHashChanges()\n\n        // Set dummy msg for consistency\n        this.set('msg', null)\n        // Set up msg listener for the optional showMsg\n        this.onChange('msg', (msg) => {\n            if (this.#isShowMsg === true) {\n                const eMsg = document.getElementById('uib_last_msg')\n                if (eMsg) eMsg.innerHTML = this.syntaxHighlight(msg)\n            }\n        })\n\n        this._dispatchCustomEvent('uibuilder:constructorComplete')\n\n        log('trace', 'Uib:constructor', 'Ending')()\n        perf.set('constructor finished', performance.now())\n    }\n\n    /** Start up Socket.IO comms and listeners\n     * This has to be done separately because if running from a web page in a sub-folder of src/dist, uibuilder cannot\n     * necessarily work out the correct ioPath to use.\n     * Also, if cookies aren't permitted in the browser, both ioPath and ioNamespace may need to be specified.\n     * @param {object} [options] The start options object.\n     * @returns {void}\n     */\n    start(options) {\n        log('trace', 'Uib:start', 'Starting')()\n        perf.set('start starting', performance.now())\n\n        // Cancel the msg event handler if already present\n        if ( this.#MsgHandler ) this.cancelChange('msg', this.#MsgHandler)\n\n        if (this.started === true) {\n            log('info', 'Uib:start', 'Start function already called. Resetting Socket.IO and msg handler.')()\n        }\n\n        // if (!document.cookie) log('error', 'uibuilder:start', 'No cookies! There should be some, is this stupid Firefox?')()\n        document.cookie.split(';').forEach((c) => {\n            const splitC = c.split('=')\n            this.cookies[splitC[0].trim()] = splitC[1]\n        })\n\n        /** Client ID set by uibuilder - lasts until browser profile is closed, applies to all tabs */\n        this.set('clientId', this.httpHeaders['uibuilder-client-id'] || this.cookies['uibuilder-client-id'] || undefined)\n        log('trace', 'Uib:constructor', 'Client ID: ', this.clientId)()\n\n        this.set('ioNamespace', this._getIOnamespace())\n\n        // console.log('window.location', window.location, this.ioNamespace)\n        // console.log('cookies: ', this.cookies, document.cookie)\n\n        /** httpNodeRoot (to set path) */\n        if (this.httpHeaders) {\n            this.set('httpNodeRoot', this.httpHeaders['uibuilder-webroot'])\n        } else if ('uibuilder-webRoot' in this.cookies) {\n            this.set('httpNodeRoot', this.cookies['uibuilder-webRoot'])\n            log('trace', 'Uib:constructor', `httpNodeRoot set by cookie to \"${this.httpNodeRoot}\"`)()\n        } else {\n            // split current url path, eliminate any blank elements and trailing or double slashes\n            const fullPath = window.location.pathname.split('/').filter(function (t) { return t.trim() !== '' }) // eslint-disable-line @stylistic/max-statements-per-line\n            /** handle url includes file name - @since v2.0.5 Extra check for 0 length, Issue #73. */\n            if (fullPath.length > 0 && fullPath[fullPath.length - 1].endsWith('.html')) fullPath.pop()\n            fullPath.pop() // gives the last path section of the url\n            this.set('httpNodeRoot', `/${fullPath.join('/')}`)\n            log('trace', '[Uib:constructor]', `httpNodeRoot set by URL parsing to \"${this.httpNodeRoot}\". NOTE: This may fail for pages in sub-folders.`)()\n        }\n        this.set('ioPath', this.urlJoin(this.httpNodeRoot, Uib._meta.displayName, 'vendor', 'socket.io'))\n        log('trace', 'Uib:constructor', `ioPath: \"${this.ioPath}\"`)()\n\n        // Work out pageName\n        this.set('pageName', window.location.pathname.replace(`${this.ioNamespace}/`, ''))\n        if ( this.pageName.endsWith('/') ) this.set('pageName', `${this.pageName}index.html`)\n        if ( this.pageName === '' ) this.set('pageName', 'index.html')\n\n        // Delay DOM monitoring by 5ms which is enough for a following script to set some values\n        // but not enough to be visible\n        setTimeout(() => {\n            // Initial scan for uib-* attributes & add suitable change processors\n            this._uibAttrScanAll(document)\n            // Observer to watch for new/changed elements & add suitable change processors\n            const observer = new MutationObserver(this._uibAttribObserver.bind(this))\n            observer.observe(document, {\n                subtree: true,\n                attributes: true,\n                attributeOldValue: true,\n                // No attributeFilter - the callback uses isUibAttribute() to filter by prefix,\n                // which is more flexible than an explicit list of attribute names.\n                childList: true,\n            })\n            perf.set('observing', performance.now())\n        }, 5)\n\n        log('log', 'Uib:start', 'Cookies: ', this.cookies, `\\nClient ID: ${this.clientId}`)()\n        log('trace', 'Uib:start', 'ioNamespace: ', this.ioNamespace, `\\nioPath: ${this.ioPath}`)()\n\n        // Handle options\n        if (options) {\n            if (options.ioNamespace) this.set('ioNamespace', options.ioNamespace)\n            if (options.ioPath) this.set('ioPath', options.ioPath)\n            if (options.nopolling && this.socketOptions.transports[0] === 'polling') this.socketOptions.transports.shift()\n        }\n\n        /** Handle specialist messages like reload and _ui -> Moved to _msgRcvdEvents */\n\n        // Track last browser navigation type: navigate, reload, back_forward, prerender\n        // TODO Needs more work - updates on navigation needed?\n        const [entry] = performance.getEntriesByType('navigation')\n        // @ts-ignore\n        this.set('lastNavType', entry.type)\n\n        // Start up (or restart) Socket.IO connections and listeners. Returns false if io not found\n        this.set('started', this._ioSetup())\n\n        if ( this.started === true ) {\n            log('trace', 'Uib:start', 'Socket.IO client library loaded.')()\n        } else {\n            log('error', 'Uib:start', 'ERROR: Socket.IO client library NOT LOADED.')()\n        }\n\n        // Check if Vue is present (used for dynamic UI processing)\n        if (window['Vue']) {\n            this.set('isVue', true)\n            try {\n                this.set('vueVersion', window['Vue'].version)\n            } catch (e) { }\n            log('trace', 'Uib:start', `VueJS is loaded. Version: ${this.vueVersion}`)()\n        } else {\n            log('trace', 'Uib:start', 'VueJS is not loaded.')()\n        }\n\n        // Check if DOMPurify library is loaded\n        if (window['DOMPurify']) {\n            this.set('purify', true)\n            log('trace', 'Uib:start', 'DOMPurify is loaded.')()\n        } else {\n            log('trace', 'Uib:start', 'DOMPurify is not loaded.')()\n        }\n        // Check if Markdown-IT library is loaded\n        if (window['markdownit']) {\n            this.set('markdown', true)\n            log('trace', 'Uib:start', 'Markdown-IT is loaded.')()\n        } else {\n            log('trace', 'Uib:start', 'Markdown-IT is not loaded.')()\n        }\n\n        this._dispatchCustomEvent('uibuilder:startComplete')\n        perf.set('start finished', performance.now())\n        // console.log('Performance: ', perf)\n    }\n\n    // #endregion -------- ------------ -------- //\n} // ==== End of Class Uib ====\n\n// #region --- Wrap up - get things started, define globals & web components ---\n\n// Create an instance (we will only ever want one)\nconst uibuilder = new Uib()\n\n// Assign reference to the instance to the global `window` object\n// Only useful if loading via <script> tag - prefer loading via `import uibuilder from ...`\nif (!window['uibuilder']) {\n    window['uibuilder'] = uibuilder\n} else {\n    log('error', 'uibuilder.module.js', '`uibuilder` already assigned to window. Have you tried to load it more than once?')\n}\nif (!window['uib']) {\n    window['uib'] = uibuilder\n} else {\n    log('warn', 'uibuilder.module.js', '`uib` shortcut already assigned to window.')\n}\n\n// Assign `$` to global window object unless it is already in use.\n// Note that this is also available as `uibuilder.$`.\nif (!window['$']) {\n    /** @type {HTMLElement} */\n    window['$'] = window['uibuilder'].$ // document.querySelector.bind(document)\n} else {\n    log('warn', 'uibuilder.module.js', 'Cannot allocate the global `$`, it is already in use. Use `uibuilder.$` or `uib.$` instead.')\n}\n// Assign `$$` to global window object unless it is already in use.\n// Note that this is also available as `uibuilder.$$`.\nif (!window['$$']) {\n    /** @type {HTMLElement} */\n    window['$$'] = window['uibuilder'].$$ // document.querySelectorAll.bind(document)\n} else {\n    log('warn', 'uibuilder.module.js', 'Cannot allocate the global `$$`, it is already in use. Use `uibuilder.$$` or `uib.$$` instead.')\n}\n\n// Assign `dom` to global window object unless it is already in use.\n// if (!window['dom']) {\n//     window['dom'] = dom\n// } else {\n//     log('warn', 'uibuilder.module.js', 'Cannot allocate the global `dom`, it is already in use. Use `uibuilder.dom` or `uib.dom` instead.')\n// }\n\n// THIS IS DONE IN THE logger.js Module (Assign `log` to global window object unless it is already in use.)\n\n// Assign `$ui` to global window object unless it is already in use.\nif (!window['$ui']) {\n    /** @type {HTMLElement} */\n    window['$ui'] = window['uibuilder'].$ui\n} else {\n    log('warn', 'uibuilder.module.js', 'Cannot allocate the global `$ui`, it is already in use. Use `uibuilder.$ui` or `uib.$ui` instead.')\n}\n\n// Try to add `on` to the standard window and document prototypes for convenience\n// This is an alias for `addEventListener`.\nif (!('on' in document)) {\n    document.on = function (event, callback) {\n        this.addEventListener(event, callback)\n    }\n}\nif (!('on' in window)) {\n    window.on = function (event, callback) {\n        this.addEventListener(event, callback)\n    }\n}\n\n// Try to add `query`, `queryAll`, and `on` to the standard Element prototype for convenience\n// These are aliases for `querySelector`, `querySelectorAll`, and `addEventListener` respectively.\ntry {\n    if (!('query' in Element)) {\n        Element.prototype.query = function(selector) {\n            return this.querySelector(selector)\n        }\n    }\n    if (!('queryAll' in Element)) {\n        Element.prototype.queryAll = function(selector) {\n            return this.querySelectorAll(selector)\n        }\n    }\n    if (!('on' in Element)) {\n        Element.prototype.on = function (event, callback) {\n            this.addEventListener(event, callback)\n        }\n    }\n} finally { } // eslint-disable-line no-empty\n\n// Can import as `import uibuilder from ...` OR `import {uibuilder} from ...`\nexport { uibuilder }\nexport default uibuilder\n\n// Attempt to run start fn only after HTTP headers are ready\ndocument.addEventListener('uibuilder:httpHeadersReady', () => {\n    uibuilder.start()\n\n    // Add built-in web component classes as a new Custom Element to the window object\n    customElements.define('uib-var', UibVar)\n    customElements.define('uib-meta', UibMeta)\n    customElements.define('apply-template', ApplyTemplate)\n    customElements.define('uib-control', UibControl)\n\n    perf.set('all done', performance.now())\n    console.log('Performance: ', perf)\n})\n\n// #endregion --- Wrap up ---\n", "// @ts-nocheck\n/**\n * @kind module\n * @module experimental\n * @description Experimental extensions to the uibuilder client library for testing future features\n *   This module extends the Uib class with experimental functionality that may be included\n *   in future releases. Use at your own risk as these features may change or be removed.\n * @license Apache-2.0\n * @author Julian Knight (Totally Information)\n * @copyright (c) 2025 Julian Knight (Totally Information)\n */\n\n// Import the base Uib class\nimport { Uib } from './uibuilder.module.mjs'\n\n// #region --- Type Definitions --- //\n/** Configuration options for experimental reactive binding\n * @typedef {object} ReactiveBindConfig\n * @property {string} [attribute] - The attribute name to bind to\n * @property {string} [variable] - The variable name to bind\n * @property {Function} [transformer] - Optional transformation function\n * @property {boolean} [twoWay] - Whether binding is two-way (default: false)\n * @property {string} [selector] - CSS selector for elements to bind\n */\n\n/** Configuration for experimental dialog component\n * @typedef {object} DialogConfig\n * @property {string} template - Template HTML or selector\n * @property {string} [title] - Dialog title\n * @property {boolean} [modal] - Whether dialog is modal (default: true)\n * @property {object} [data] - Data to pass to template\n * @property {Function} [onClose] - Callback when dialog closes\n */\n// #endregion --- Type Definitions --- //\n\n/**\n * Experimental extensions to the Uib class\n * Provides experimental features for testing future functionality\n * @class UibExperimental\n * @augments Uib\n */\nexport class UibExperimental extends Uib {\n    /** @type {object} Experimental metadata */\n    static _experimentalMeta = {\n        version: '7.5.0-experimental',\n        features: 'reactive-binding,enhanced-dialogs,auto-layout,template-engine',\n        warning: 'Experimental features - subject to change or removal',\n    }\n\n    // #region --- Private experimental properties --- //\n\n    /** @type {Map<string, ReactiveBindConfig>} Reactive binding configurations */\n    #reactiveBindings = new Map()\n\n    /** @type {MutationObserver} Observer for reactive attribute changes */\n    #reactiveObserver = null\n\n    /** @type {Set<HTMLElement>} Elements with experimental attributes */\n    #experimentalElements = new Set()\n\n    /** @type {Object<string, HTMLDialogElement>} Active dialogs */\n    #activeDialogs = {}\n\n    /** @type {number} Counter for unique dialog IDs */\n    #dialogCounter = 0\n\n    /** @type {Map<string, Set<HTMLElement>>} Track elements that use specific variables in templates */\n    #templateVariableMap = new Map()\n\n    /** @type {Map<HTMLElement, object>} Track template data for each element */\n    #templateDataMap = new Map()\n\n    /** @type {Map<HTMLElement, string>} Track original template strings for each element */\n    #templateStringMap = new Map()\n\n    // #endregion --- Private experimental properties --- //\n\n    constructor() {\n        super()\n\n        // Initialize experimental features\n        this._initExperimentalFeatures()\n\n        // Dispatch experimental ready event\n        if (this._dispatchCustomEvent) {\n            this._dispatchCustomEvent('uibuilder:experimentalReady', {\n                features: UibExperimental._experimentalMeta.features,\n                version: UibExperimental._experimentalMeta.version,\n            })\n        }\n    }\n\n    // #region --- Experimental Feature Initialization --- //\n\n    /** Initialize all experimental features */\n    _initExperimentalFeatures() {\n        this._initReactiveBinding()\n        this._initExperimentalAttributes()\n        this._initDialogSupport()\n\n        // Log experimental mode activation\n        console.warn('[UibExperimental] Experimental mode activated. Features may change or be removed.', UibExperimental._experimentalMeta)\n        console.info('[UibExperimental] Available features:', UibExperimental._experimentalMeta.features.split(','))\n    }\n\n    /** Initialize reactive binding system */\n    _initReactiveBinding() {\n        // Create mutation observer for reactive attributes\n        this.#reactiveObserver = new MutationObserver((mutations) => {\n            mutations.forEach((mutation) => {\n                if (mutation.type === 'attributes' && mutation.target instanceof HTMLElement) {\n                    this._handleReactiveAttributeChange(mutation.target, mutation.attributeName)\n                } else if (mutation.type === 'childList') {\n                    // Handle new elements added to DOM\n                    mutation.addedNodes.forEach((node) => {\n                        if (node.nodeType === Node.ELEMENT_NODE && node instanceof HTMLElement) {\n                            this._scanForExperimentalAttributes(node)\n                        }\n                    })\n                }\n            })\n        })\n\n        // Start observing\n        this.#reactiveObserver.observe(document.body, {\n            attributes: true,\n            childList: true,\n            subtree: true,\n            attributeFilter: ['uib-bind', 'uib-on', 'uib-show', 'uib-text', 'uib-model'],\n        })\n    }\n\n    /** Initialize support for experimental attributes */\n    _initExperimentalAttributes() {\n        // Scan existing DOM for experimental attributes\n        this._scanForExperimentalAttributes(document.body)\n    }\n\n    /** Initialize enhanced dialog support */\n    _initDialogSupport() {\n        // Ensure native dialog support or polyfill\n        if (!HTMLDialogElement) {\n            console.warn('[UibExperimental] Native dialog not supported. Consider adding a polyfill.')\n        }\n    }\n\n    // #endregion --- Experimental Feature Initialization --- //\n\n    // #region --- Reactive Binding Experimental Features --- //\n\n    /**\n     * Create a reactive binding between a variable and DOM elements\n     * @param {string} variable - Variable name to bind\n     * @param {string} selector - CSS selector for elements to bind\n     * @param {ReactiveBindConfig} config - Binding configuration\n     * @returns {void}\n     * @example\n     * uibExperimental.createReactiveBinding('userName', '[uib-bind=\"userName\"]', {\n     *     attribute: 'textContent',\n     *     twoWay: false\n     * })\n     */\n    createReactiveBinding(variable, selector, config = {}) {\n        const bindingId = `${variable}:${selector}`\n        const bindingConfig = {\n            variable,\n            selector,\n            attribute: config.attribute || 'textContent',\n            transformer: config.transformer || (val => val),\n            twoWay: config.twoWay || false,\n            ...config,\n        }\n\n        this.#reactiveBindings.set(bindingId, bindingConfig)\n\n        // Apply initial binding\n        this._applyReactiveBinding(bindingConfig)\n\n        // Watch for variable changes\n        this.onChange(variable, (newValue) => {\n            this._applyReactiveBinding(bindingConfig, newValue)\n        })\n    }\n\n    /**\n     * Apply reactive binding to DOM elements\n     * @param {ReactiveBindConfig} config - Binding configuration\n     * @param {*} [value] - Optional value to set\n     * @private\n     */\n    _applyReactiveBinding(config, value) {\n        const elements = document.querySelectorAll(config.selector)\n        const currentValue = value !== undefined ? value : this.get(config.variable)\n        const transformedValue = config.transformer(currentValue)\n\n        elements.forEach((element) => {\n            if (config.attribute === 'textContent') {\n                element.textContent = transformedValue\n            } else if (config.attribute === 'innerHTML') {\n                element.innerHTML = transformedValue\n            } else if (config.attribute.startsWith('data-')) {\n                element.setAttribute(config.attribute, transformedValue)\n            } else {\n                element[config.attribute] = transformedValue\n            }\n\n            // Set up two-way binding for input elements\n            if (config.twoWay && element.tagName === 'INPUT') {\n                element.addEventListener('input', (event) => {\n                    this.set(config.variable, event.target.value)\n                })\n            }\n\n            this.#experimentalElements.add(element)\n        })\n    }\n\n    /**\n     * Handle reactive attribute changes\n     * @param {HTMLElement} element - Element that changed\n     * @param {string} attributeName - Name of changed attribute\n     * @private\n     */\n    _handleReactiveAttributeChange(element, attributeName) {\n        if (attributeName === 'uib-bind') {\n            const variable = element.getAttribute('uib-bind')\n            if (variable) {\n                const value = this.get(variable)\n                element.textContent = value\n            }\n        } else if (attributeName === 'uib-show') {\n            const variable = element.getAttribute('uib-show')\n            if (variable) {\n                const value = this.get(variable)\n                if (element instanceof HTMLElement) {\n                    element.style.display = value ? 'block' : 'none'\n                }\n            }\n        }\n    }\n\n    /**\n     * Scan for experimental attributes in DOM\n     * @param {HTMLElement} root - Root element to scan from\n     * @private\n     */\n    _scanForExperimentalAttributes(root) {\n        // Scan for uib-bind attributes\n        const bindElements = root.querySelectorAll('[uib-bind]')\n        bindElements.forEach((element) => {\n            const variable = element.getAttribute('uib-bind')\n            if (variable) {\n                this.createReactiveBinding(variable, `[uib-bind=\"${variable}\"]`)\n            }\n        })\n\n        // Scan for uib-show attributes\n        const showElements = root.querySelectorAll('[uib-show]')\n        showElements.forEach((element) => {\n            const variable = element.getAttribute('uib-show')\n            if (variable) {\n                this.onChange(variable, (value) => {\n                    element.style.display = value ? 'block' : 'none'\n                })\n            }\n        })\n    }\n\n    // #endregion --- Reactive Binding Experimental Features --- //\n\n    // #region --- Enhanced Dialog Experimental Features --- //\n\n    /** Create and show an experimental dialog\n     * @param {DialogConfig} config - Dialog configuration\n     * @returns {Promise<any>} Promise that resolves when dialog closes\n     * @example\n     * const result = await uibExperimental.showExperimentalDialog({\n     *     template: '<p>Are you sure?</p>',\n     *     title: 'Confirmation',\n     *     modal: true\n     * })\n     */\n    async showExperimentalDialog(config) {\n        return new Promise((resolve) => {\n            const dialogId = `exp-dialog-${++this.#dialogCounter}`\n            const dialog = this._createDialog(dialogId, config)\n\n            // Store dialog reference\n            this.#activeDialogs[dialogId] = dialog\n\n            // Handle dialog close\n            const handleClose = (result) => {\n                delete this.#activeDialogs[dialogId]\n                dialog.remove()\n                if (config.onClose) config.onClose(result)\n                resolve(result)\n            }\n\n            // Add close event listeners\n            dialog.addEventListener('close', () => handleClose(dialog.returnValue))\n\n            // Add to DOM and show\n            document.body.appendChild(dialog)\n            dialog.showModal()\n        })\n    }\n\n    /** Create a dialog element\n     * @param {string} dialogId - Unique dialog ID\n     * @param {DialogConfig} config - Dialog configuration\n     * @returns {HTMLDialogElement} Created dialog element\n     * @private\n     */\n    _createDialog(dialogId, config) {\n        const dialog = document.createElement('dialog')\n        dialog.id = dialogId\n        dialog.className = 'uib-experimental-dialog'\n\n        // Build dialog content\n        let content = ''\n        if (config.title) {\n            content += `<header class=\"uib-dialog-header\">\n                <h2>${config.title}</h2>\n                <button type=\"button\" class=\"uib-dialog-close\" aria-label=\"Close\">&times;</button>\n            </header>`\n        }\n\n        content += `<main class=\"uib-dialog-content\">`\n\n        // Handle template\n        if (config.template.trim().startsWith('<')) {\n            // Direct HTML\n            content += config.template\n        } else {\n            // Selector - get template from DOM\n            const templateElement = document.querySelector(config.template)\n            if (templateElement) {\n                content += templateElement.innerHTML\n            } else {\n                content += config.template\n            }\n        }\n\n        content += `</main>`\n\n        // Add default buttons if not present in template\n        if (!config.template.includes('button')) {\n            content += `<footer class=\"uib-dialog-footer\">\n                <button type=\"button\" value=\"cancel\">Cancel</button>\n                <button type=\"button\" value=\"ok\" class=\"uib-primary\">OK</button>\n            </footer>`\n        }\n\n        dialog.innerHTML = content\n\n        // Add event listeners\n        dialog.addEventListener('click', (event) => {\n            const target = event.target\n            if (target && 'matches' in target && target.matches('button[value]')) {\n                dialog.returnValue = target.value\n                dialog.close()\n            } else if (target && 'matches' in target && target.matches('.uib-dialog-close')) {\n                dialog.returnValue = 'cancel'\n                dialog.close()\n            }\n        })\n\n        // Close on backdrop click if modal\n        if (config.modal !== false) {\n            dialog.addEventListener('click', (event) => {\n                if (event.target === dialog) {\n                    dialog.returnValue = 'cancel'\n                    dialog.close()\n                }\n            })\n        }\n\n        return dialog\n    }\n\n    /** Close all experimental dialogs\n     * @returns {void}\n     */\n    closeAllDialogs() {\n        Object.values(this.#activeDialogs).forEach((dialog) => {\n            dialog.close()\n        })\n    }\n\n    // #endregion --- Enhanced Dialog Experimental Features --- //\n\n    // #region --- Template Engine Experimental Features --- //\n\n    /** Process a template with data using experimental template engine\n     * @param {string} template - Template string with {{variable}} syntax\n     * @param {object} data - Data object to interpolate\n     * @param {HTMLElement} [targetElement] - Optional element to bind for auto-updates\n     * @returns {string} Processed template\n     * @example\n     * const result = uibExperimental.processTemplate(\n     *     '<p>Hello {{name}}!</p>',\n     *     { name: 'World' }\n     * )\n     *\n     * // With auto-update binding\n     * const element = document.getElementById('greeting')\n     * element.innerHTML = uibExperimental.processTemplate(\n     *     '<p>Hello {{userName}}! Today is {{date}}.</p>',\n     *     { userName: 'John', date: new Date().toLocaleDateString() },\n     *     element\n     * )\n     */\n    processTemplate(template, data = {}, targetElement = null) {\n        // Extract variable names from template\n        const variables = this._extractTemplateVariables(template)\n\n        // If we have a target element, set up auto-update\n        if (targetElement) {\n            this._setupTemplateAutoUpdate(targetElement, template, data, variables)\n        }\n\n        // Process the template\n        return this._renderTemplate(template, data)\n    }\n\n    /** Extract variable names from a template string\n     * @param {string} template - Template string with {{variable}} syntax\n     * @returns {string[]} Array of variable names found in template\n     * @private\n     */\n    _extractTemplateVariables(template) {\n        const variables = []\n        const regex = /\\{\\{([^}]+)\\}\\}/g\n        let match\n\n        while ((match = regex.exec(template)) !== null) {\n            const variable = match[1].trim()\n            if (!variables.includes(variable)) {\n                variables.push(variable)\n            }\n        }\n\n        return variables\n    }\n\n    /** Set up auto-update for a template bound to an element\n     * @param {HTMLElement} element - Target element for template\n     * @param {string} template - Template string\n     * @param {object} data - Template data\n     * @param {string[]} variables - Variable names used in template\n     * @private\n     */\n    _setupTemplateAutoUpdate(element, template, data, variables) {\n        // Store template information for this element\n        this.#templateStringMap.set(element, template)\n        this.#templateDataMap.set(element, { ...data, })\n\n        // Track which variables this element depends on\n        variables.forEach((variable) => {\n            const rootVar = variable.split('.')[0] // Get root variable name\n\n            if (!this.#templateVariableMap.has(rootVar)) {\n                this.#templateVariableMap.set(rootVar, new Set())\n            }\n            this.#templateVariableMap.get(rootVar).add(element)\n\n            // Set up change listener for this variable if not already set\n            this._ensureVariableListener(rootVar)\n        })\n    }\n\n    /** Ensure a change listener exists for a variable\n     * @param {string} variable - Variable name to watch\n     * @private\n     */\n    _ensureVariableListener(variable) {\n        // Check if we already have a listener for this variable\n        const existingListeners = this._propChangeCallbacks || {}\n        if (existingListeners[variable]) {\n            // Check if our template update listener is already registered\n            const hasTemplateListener = existingListeners[variable].some(\n                cb => cb.name === '_templateUpdateListener'\n            )\n            if (hasTemplateListener) return\n        }\n\n        // Add our template update listener\n        this.onChange(variable, this._createTemplateUpdateListener(variable))\n    }\n\n    /**\n     * Create a template update listener for a specific variable\n     * @param {string} variable - Variable name being watched\n     * @returns {Function} Update listener function\n     * @private\n     */\n    _createTemplateUpdateListener(variable) {\n        const listener = (newValue) => {\n            // Find all elements that use this variable\n            const elements = this.#templateVariableMap.get(variable)\n            if (!elements) return\n\n            elements.forEach((element) => {\n                // Update the stored data for this element\n                const storedData = this.#templateDataMap.get(element)\n                if (storedData) {\n                    storedData[variable] = newValue\n\n                    // Re-render the template\n                    const template = this.#templateStringMap.get(element)\n                    if (template) {\n                        const newContent = this._renderTemplate(template, storedData)\n                        element.innerHTML = newContent\n                    }\n                }\n            })\n        }\n\n        // Add a name property for identification\n        Object.defineProperty(listener, 'name', { value: '_templateUpdateListener', })\n\n        return listener\n    }\n\n    /**\n     * Render a template with data (core template processing)\n     * @param {string} template - Template string with {{variable}} syntax\n     * @param {object} data - Data object to interpolate\n     * @returns {string} Processed template\n     * @private\n     */\n    _renderTemplate(template, data) {\n        return template.replace(/\\{\\{([^}]+)\\}\\}/g, (match, variable) => {\n            const keys = variable.trim().split('.')\n            let value = data\n\n            for (const key of keys) {\n                value = value?.[key]\n                if (value === undefined) break\n            }\n\n            return value !== undefined ? String(value) : match\n        })\n    }\n\n    /**\n     * Update template data for an element (triggers re-render)\n     * @param {HTMLElement} element - Element with bound template\n     * @param {object} newData - New data to merge with existing data\n     * @returns {void}\n     * @example\n     * uibExperimental.updateTemplateData(element, { userName: 'Jane' })\n     */\n    updateTemplateData(element, newData) {\n        const storedData = this.#templateDataMap.get(element)\n        if (!storedData) {\n            console.warn('[UibExperimental] No template data found for element')\n            return\n        }\n\n        // Merge new data with existing data\n        Object.assign(storedData, newData)\n\n        // Re-render the template\n        const template = this.#templateStringMap.get(element)\n        if (template) {\n            const newContent = this._renderTemplate(template, storedData)\n            element.innerHTML = newContent\n        }\n\n        // Update any uibuilder variables that changed\n        Object.entries(newData).forEach(([key, value]) => {\n            this.set(key, value)\n        })\n    }\n\n    /**\n     * Remove template binding from an element\n     * @param {HTMLElement} element - Element to unbind\n     * @returns {void}\n     */\n    unbindTemplate(element) {\n        // Remove from template maps\n        this.#templateStringMap.delete(element)\n        this.#templateDataMap.delete(element)\n\n        // Remove from variable tracking\n        this.#templateVariableMap.forEach((elements) => {\n            elements.delete(element)\n        })\n    }\n\n    /** Apply template to elements with uib-template attribute\n     * @param {object} data - Data object for template interpolation\n     * @param {boolean} autoUpdate - Whether to enable auto-updates when variables change (default: true)\n     * @returns {void}\n     */\n    applyTemplates(data = {}, autoUpdate = true) {\n        const templateElements = document.querySelectorAll('[uib-template]')\n\n        templateElements.forEach((element) => {\n            const templateSelector = element.getAttribute('uib-template')\n            const templateElement = document.querySelector(templateSelector)\n\n            if (templateElement) {\n                const template = templateElement.innerHTML\n\n                if (autoUpdate) {\n                    // Use the new auto-update processTemplate\n                    const processed = this.processTemplate(template, data, element)\n                    element.innerHTML = processed\n                } else {\n                    // Use simple template processing without auto-update\n                    const processed = this._renderTemplate(template, data)\n                    element.innerHTML = processed\n                }\n            } else {\n                console.warn(`[UibExperimental] Template element not found for selector: \"${templateSelector}\"`)\n            }\n        })\n    }\n\n    // #endregion --- Template Engine Experimental Features --- //\n\n    // #region --- Auto Layout Experimental Features --- //\n\n    /** Apply experimental auto-layout to container elements\n     * @param {string} selector - CSS selector for containers\n     * @param {object} options - Layout options\n     * @returns {void}\n     * @example\n     * uibExperimental.applyAutoLayout('.auto-grid', {\n     *     type: 'grid',\n     *     columns: 'auto-fit',\n     *     gap: '1rem'\n     * })\n     */\n    applyAutoLayout(selector, options = {}) {\n        const containers = document.querySelectorAll(selector)\n\n        containers.forEach((container) => {\n            if (!(container instanceof HTMLElement)) return\n\n            const layoutType = options.type || 'flex'\n\n            if (layoutType === 'grid') {\n                container.style.display = 'grid'\n                container.style.gridTemplateColumns = options.columns || 'repeat(auto-fit, minmax(200px, 1fr))'\n                container.style.gap = options.gap || '1rem'\n            } else if (layoutType === 'flex') {\n                container.style.display = 'flex'\n                container.style.flexWrap = options.wrap || 'wrap'\n                container.style.gap = options.gap || '1rem'\n                container.style.justifyContent = options.justify || 'space-between'\n            }\n\n            // Add responsive behavior\n            if (options.responsive !== false) {\n                this._addResponsiveLayout(container, layoutType, options)\n            }\n        })\n    }\n\n    /** Add responsive behavior to layout\n     * @param {HTMLElement} container - Container element\n     * @param {string} layoutType - Type of layout\n     * @param {object} options - Layout options\n     * @private\n     */\n    _addResponsiveLayout(container, layoutType, options) {\n        const resizeObserver = new ResizeObserver((entries) => {\n            for (const entry of entries) {\n                const width = entry.contentRect.width\n\n                if (layoutType === 'grid') {\n                    // Adjust grid columns based on width\n                    const minColumnWidth = options.minColumnWidth || 200\n                    const columns = Math.floor(width / minColumnWidth) || 1\n                    container.style.gridTemplateColumns = `repeat(${columns}, 1fr)`\n                } else if (layoutType === 'flex') {\n                    // Adjust flex direction based on width\n                    if (width < (options.breakpoint || 768)) {\n                        container.style.flexDirection = 'column'\n                    } else {\n                        container.style.flexDirection = 'row'\n                    }\n                }\n            }\n        })\n\n        resizeObserver.observe(container)\n    }\n\n    // #endregion --- Auto Layout Experimental Features --- //\n\n    // #region --- Utility Methods --- //\n\n    /** Get experimental metadata\n     * @returns {object} Experimental metadata\n     */\n    getExperimentalMeta() {\n        return UibExperimental._experimentalMeta\n    }\n\n    /** Check if an experimental feature is available\n     * @param {string} feature - Feature name to check\n     * @returns {boolean} Whether feature is available\n     */\n    hasExperimentalFeature(feature) {\n        return UibExperimental._experimentalMeta.features.split(',').includes(feature)\n    }\n\n    /** Enable experimental debug mode\n     * @param {boolean} enabled - Whether to enable debug mode (default: true)\n     * @returns {void}\n     */\n    setExperimentalDebug(enabled = true) {\n        if (enabled) {\n            console.info('[UibExperimental] Debug mode enabled')\n            if (typeof window !== 'undefined') {\n                window.uibExpDebug = {\n                    bindings: this.#reactiveBindings,\n                    elements: this.#experimentalElements,\n                    dialogs: this.#activeDialogs,\n                }\n            }\n        } else {\n            if (typeof window !== 'undefined' && 'uibExpDebug' in window) {\n                delete window.uibExpDebug\n            }\n        }\n    }\n\n    /** Clean up experimental features\n     * @returns {void}\n     */\n    cleanup() {\n        // Disconnect observers\n        this.#reactiveObserver?.disconnect()\n\n        // Close all dialogs\n        this.closeAllDialogs()\n\n        // Clear experimental elements\n        this.#experimentalElements.clear()\n\n        // Clear bindings\n        this.#reactiveBindings.clear()\n\n        // Clear template tracking\n        this.#templateVariableMap.clear()\n        this.#templateDataMap.clear()\n        this.#templateStringMap.clear()\n\n        console.info('[UibExperimental] Cleanup completed')\n    }\n\n    // #endregion --- Utility Methods --- //\n}\n\n// Create experimental instance\nconst uibExperimental = new UibExperimental()\n\n// Export both class and instance\nexport { uibExperimental }\nexport default uibExperimental\n\n// Add to global scope for script tag usage\nif (typeof window !== 'undefined') {\n    window.uibExperimental = uibExperimental\n}\n"],
  "mappings": "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",
  "names": ["showOverlay", "options", "content", "title", "icon", "type", "showDismiss", "autoClose", "time", "overlayContainerId", "overlayContainer", "entryId", "overlayEntry", "typeStyles", "currentTypeStyle", "shouldShowDismiss", "iconHtml", "titleText", "timeHtml", "now", "year", "month", "day", "hours", "minutes", "seconds", "timestamp", "closeOverlayEntry", "entry", "dismissBtn", "autoCloseTimer", "_a", "Ui", "win", "extLog", "jsonHighlight", "__publicField", "str", "lang", "high", "plugin", "name", "config", "notify", "resolve", "reject", "ev", "ui", "isRecurse", "compToAdd", "i", "newEl", "elParent", "el", "comp", "attrib", "type", "evt", "err", "prop", "parentEl", "components", "ns", "component", "__toESM", "__require", "script", "sheet", "msg", "all", "compToRemove", "els", "compToReplace", "elToReplace", "compToUpd", "elToUpd", "j", "nc", "nestedComp", "k", "method", "cssSelector", "output", "context", "out", "attr", "e", "classNames", "sourceId", "targetId", "template", "target", "targetContent", "templateContent", "slot", "mdText", "url", "uiOptions", "response", "error", "contentType", "txtReturn", "data", "newScript", "textFn", "newStyle", "opts", "sourceSelector", "targetSelector", "moveType", "position", "node", "thisOut", "listEntries", "bodyEntries", "headEntries", "cols", "v", "permit", "tempFrag", "elRange", "html", "body", "title", "content", "icon", "removeToaster", "toaster", "toasterEventHandler", "removeToast", "localToast", "newToast", "toastEventHandler", "hasInteractiveElement", "lastToast", "options", "showOverlay", "json", "propName", "selection", "p", "cType", "key", "rowKeys", "dataType", "tbl", "thead", "headerRow", "hasName", "col", "thEl", "tbody", "rowOpts", "item", "rowData", "tblType", "tblEl", "tbodyEl", "colMeta", "rowEl", "cellEl", "colKey", "row", "foundEl", "foundRowData", "numColKey", "afterRow", "beforeRow", "replaceRow", "tblSelector", "table", "event", "clickedRow", "clickedCell", "rowIndex", "cellIndex", "cell", "colName", "rowKey", "colDef", "find", "c", "pad", "_b", "_c", "colData", "colIndex", "ui_default", "PACKET_TYPES", "PACKET_TYPES_REVERSE", "key", "ERROR_PACKET", "withNativeBlob", "withNativeArrayBuffer", "isView", "obj", "encodePacket", "type", "data", "supportsBinary", "callback", "encodeBlobAsBase64", "PACKET_TYPES", "fileReader", "content", "toArray", "TEXT_ENCODER", "encodePacketToBinary", "packet", "encoded", "chars", "lookup", "i", "decode", "base64", "bufferLength", "len", "p", "encoded1", "encoded2", "encoded3", "encoded4", "arraybuffer", "bytes", "lookup", "withNativeArrayBuffer", "decodePacket", "encodedPacket", "binaryType", "mapBinary", "type", "decodeBase64Packet", "PACKET_TYPES_REVERSE", "ERROR_PACKET", "data", "decoded", "decode", "SEPARATOR", "encodePayload", "packets", "callback", "length", "encodedPackets", "count", "packet", "i", "encodePacket", "encodedPacket", "decodePayload", "encodedPayload", "binaryType", "decodedPacket", "decodePacket", "createPacketEncoderStream", "controller", "encodePacketToBinary", "payloadLength", "header", "view", "TEXT_DECODER", "totalLength", "chunks", "acc", "chunk", "concatChunks", "size", "buffer", "j", "createPacketDecoderStream", "maxPayload", "state", "expectedLength", "isBinary", "headerArray", "n", "ERROR_PACKET", "data", "protocol", "Emitter", "obj", "mixin", "key", "event", "fn", "on", "callbacks", "cb", "i", "args", "len", "nextTick", "cb", "setTimeoutFn", "globalThisShim", "defaultBinaryType", "pick", "obj", "attr", "acc", "k", "NATIVE_SET_TIMEOUT", "globalThisShim", "NATIVE_CLEAR_TIMEOUT", "installTimerFunctions", "opts", "BASE64_OVERHEAD", "byteLength", "utf8Length", "str", "c", "length", "l", "randomString", "encode", "obj", "str", "i", "decode", "qs", "qry", "pairs", "l", "pair", "TransportError", "reason", "description", "context", "Transport", "Emitter", "opts", "installTimerFunctions", "packets", "data", "packet", "decodePacket", "details", "onPause", "schema", "query", "hostname", "encodedQuery", "encode", "Polling", "Transport", "onPause", "pause", "total", "data", "callback", "packet", "decodePayload", "close", "packets", "encodePayload", "schema", "query", "randomString", "value", "hasCORS", "empty", "BaseXHR", "Polling", "opts", "isSSL", "port", "data", "fn", "req", "xhrStatus", "context", "Request", "_Request", "Emitter", "createRequest", "uri", "installTimerFunctions", "_a", "pick", "xhr", "i", "e", "err", "fromError", "unloadHandler", "terminationEvent", "globalThisShim", "hasXHR2", "newRequest", "XHR", "forceBase64", "xdomain", "hasCORS", "isReactNative", "BaseWS", "Transport", "uri", "protocols", "opts", "pick", "err", "closeEvent", "ev", "packets", "i", "packet", "lastPacket", "encodePacket", "data", "nextTick", "schema", "query", "randomString", "WebSocketCtor", "globalThisShim", "WS", "_packet", "WT", "Transport", "err", "stream", "decoderStream", "createPacketDecoderStream", "reader", "encoderStream", "createPacketEncoderStream", "read", "done", "value", "packet", "packets", "i", "lastPacket", "nextTick", "_a", "transports", "WS", "WT", "XHR", "re", "parts", "parse", "str", "src", "b", "e", "m", "uri", "i", "pathNames", "queryKey", "obj", "path", "regx", "names", "query", "data", "$0", "$1", "$2", "withEventListeners", "OFFLINE_EVENT_LISTENERS", "listener", "SocketWithoutUpgrade", "_SocketWithoutUpgrade", "Emitter", "uri", "opts", "defaultBinaryType", "parsedUri", "parse", "installTimerFunctions", "t", "transportName", "decode", "name", "query", "protocol", "transport", "reason", "packet", "err", "data", "delay", "packets", "payloadSize", "byteLength", "hasExpired", "nextTick", "msg", "options", "fn", "type", "close", "cleanupAndClose", "waitForUpgrade", "description", "SocketWithUpgrade", "i", "failed", "onTransportOpen", "cleanup", "freezeTransport", "onerror", "error", "onTransportClose", "onclose", "onupgrade", "to", "upgrades", "filteredUpgrades", "Socket", "o", "transports", "protocol", "Socket", "url", "uri", "path", "loc", "obj", "parse", "host", "esm_exports", "__export", "Decoder", "Encoder", "PacketType", "isPacketValid", "protocol", "withNativeArrayBuffer", "isView", "obj", "toString", "withNativeBlob", "withNativeFile", "isBinary", "hasBinary", "toJSON", "i", "l", "key", "deconstructPacket", "packet", "buffers", "packetData", "pack", "_deconstructPacket", "data", "isBinary", "placeholder", "newData", "key", "reconstructPacket", "_reconstructPacket", "i", "RESERVED_EVENTS", "protocol", "PacketType", "Encoder", "replacer", "obj", "hasBinary", "str", "deconstruction", "deconstructPacket", "pack", "buffers", "Decoder", "_Decoder", "Emitter", "opts", "packet", "isBinaryEvent", "BinaryReconstructor", "isBinary", "i", "p", "start", "buf", "n", "isInteger", "next", "c", "payload", "type", "isObject", "binData", "reconstructPacket", "isNamespaceValid", "nsp", "value", "isAckIdValid", "id", "isDataValid", "isPacketValid", "on", "obj", "ev", "fn", "RESERVED_EVENTS", "Socket", "Emitter", "io", "nsp", "opts", "on", "args", "ev", "_a", "_b", "_c", "packet", "PacketType", "id", "ack", "isTransportWritable", "isConnected", "timeout", "timer", "i", "fn", "resolve", "reject", "arg1", "arg2", "err", "responseArgs", "force", "data", "reason", "description", "listeners", "listener", "self", "sent", "pid", "subDestroy", "compress", "Backoff", "opts", "ms", "rand", "deviation", "min", "max", "jitter", "Manager", "Emitter", "uri", "opts", "_a", "installTimerFunctions", "Backoff", "_parser", "esm_exports", "v", "fn", "Socket", "socket", "self", "openSubDestroy", "on", "onError", "err", "errorSub", "timeout", "timer", "data", "e", "packet", "nextTick", "nsp", "nsps", "encodedPackets", "subDestroy", "reason", "description", "delay", "attempt", "cache", "lookup", "uri", "opts", "parsed", "url", "source", "id", "path", "sameNamespace", "newConnection", "io", "Manager", "Socket", "_HTMLElement", "_TiBaseComponent", "__publicField", "config", "_a", "_b", "target", "sources", "source", "k", "vs", "vt", "url", "linkEl", "node", "cssText", "order", "existingStylesheet", "styleElement", "evtName", "data", "template", "shadowOpts", "msg", "key", "key2", "head", "existingComponentStyles", "firstChild", "insertBefore", "existing", "existingOrder", "nextSibling", "TiBaseComponent", "ti_base_component_default", "_variable", "_varCb", "_topic", "_topicCb", "UibVar", "ti_base_component_default", "__privateAdd", "__publicField", "varName", "__privateSet", "e", "__privateGet", "topicName", "topic", "attrib", "oldVal", "newVal", "f", "x", "y", "value", "success", "target", "partSuccess", "part", "successPart", "msg", "chkVal", "val", "out", "li", "div", "t", "splitFilter", "globalFn", "argList", "uib_var_default", "UibMeta", "ti_base_component_default", "__publicField", "attrib", "oldVal", "newVal", "val", "chkVal", "out", "type", "uib_meta_default", "ApplyTemplate", "ti_base_component_default", "__publicField", "templateId", "onceOnly", "template", "existContent", "templateContent", "slot", "attrib", "oldVal", "newVal", "apply_template_default", "template", "_uniqueKey", "_toggleButton", "_dragHandlers", "_toggleHandlers", "_resizeHandler", "UibControl", "ti_base_component_default", "__privateAdd", "_a", "_b", "toggleButton", "__privateSet", "contentBox", "isExpanded", "clickHandler", "keydownHandler", "evt", "touchStartTime", "touchStartX", "touchStartY", "touchStartHandler", "touchEndHandler", "touchEndTime", "touchEndX", "touchEndY", "duration", "distance", "__privateGet", "outsideClickHandler", "themeButtonsContainer", "themeButtons", "currentTheme", "themeChangeHandler", "selectedTheme", "buttons", "activeTheme", "button", "_c", "tabNavigation", "tabButtons", "tabPanels", "tabClickHandler", "clickedButton", "targetPanelId", "panel", "tabKeyHandler", "currentIndex", "targetIndex", "targetButton", "htmlElement", "savedTheme", "error", "theme", "container", "isDragging", "dragStarted", "startX", "startY", "initialX", "initialY", "dragThreshold", "startDrag", "clientX", "clientY", "rect", "mouseMove", "deltaX", "deltaY", "newX", "newY", "maxX", "maxY", "constrainedX", "constrainedY", "mouseUp", "wasDragStarted", "touchMove", "touch", "touchEnd", "saveKey", "position", "savedData", "width", "height", "viewportEl", "clientEl", "attrib", "oldVal", "newVal", "__publicField", "uib_control_default", "Reactive", "srcvar", "obj", "propertyPath", "value", "oldValue", "target", "callback", "error", "basePath", "key", "receiver", "listenerId", "listenerRef", "result", "newPath", "hadKey", "title", "details", "event", "__publicField", "reactive", "FORMATTER_CACHE", "getFormatter", "locale", "options", "key", "getParts", "date", "formatter", "p", "getNames", "formatDate", "pattern", "parts", "names", "tokens", "token", "perf", "__uibHeadersPromise", "r", "h", "v", "k", "version", "isMinified", "param", "log", "args", "level", "strLevel", "head", "ll", "scriptElement", "syntaxHighlight", "json", "match", "cls", "_ui", "ui_default", "_a", "_pingInterval", "_propChangeCallbacks", "_msgRecvdByTopicCallbacks", "_timerid", "_manualDisconnect", "_MsgHandler", "_isShowMsg", "_isShowStatus", "_sendUrlHash", "_uniqueElID", "_extCommands", "_managedVars", "_showStatus", "_uiObservers", "_uibAttrSel", "Uib", "__publicField", "__privateAdd", "cb", "formatDate", "headers", "event", "__privateGet", "autoloadVars", "id", "msg", "eMsg", "prop", "isNestedPath", "nestedPath", "rootProp", "dotIdx", "bracketIdx", "sepIdx", "val", "store", "autoload", "oldVal", "eventProp", "eventVal", "value", "autoVars", "e", "title", "details", "callback", "nextCbRef", "propChangeCallback", "cbRef", "topic", "msgRecvdEvtCallback", "receivedMsg", "serverTimestamp", "offset", "a1", "a2", "uName", "varToCopy", "data", "cssSelector", "el", "exists", "decimalPlaces", "intl", "opts", "out", "obj", "size", "jsonString", "name", "url", "stack", "thing", "property", "srcvar", "reactive", "Reactive", "path", "parts", "part", "error", "num", "p", "n", "originator", "ms", "oReq", "elapsedTime", "__privateSet", "_stackMapChromium", "line", "raw", "_stackMapFirefox", "_stackMapSafari", "type", "deflt", "ret", "toggle", "mdText", "uiOptions", "textFn", "slot", "component", "html", "options", "tblSelector", "tbl", "rowData", "rowIndex", "ui", "propName", "mutations", "mlen", "m", "nlen", "i", "a", "elToCheck", "len", "key", "hasChecked", "hasValue", "keys", "current", "finalKey", "varName", "hasSubPath", "doVar", "rootValue", "expr", "result", "expression", "context", "maxRetries", "retryDelay", "defaultValue", "evaluator", "attempt", "resolve", "bindName", "bindValue", "uibAttribs", "attr", "alen", "parentEl", "uibChildren", "srcEl", "noSend", "files", "seqCount", "seq", "file", "props", "meta", "ignoreAttribs", "attribs", "classes", "checked", "option", "formDetails", "config", "res", "err", "__privateWrapper", "showHide", "parent", "root", "entry", "startStop", "send", "showLog", "targetNode", "that", "mutationList", "mu", "oMu", "an", "htmlCache", "receivedCtrlMsg", "ts", "msgToSend", "channel", "numMsgs", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "_i", "cmd", "quiet", "response", "info", "newUrl", "timeout", "onSuccess", "correlationId", "reject", "cleanup", "tid", "lref", "timeoutId", "listenerRef", "responseMsg", "txtToSend", "logLevel", "domevent", "target", "payload", "frmEl", "nprops", "room", "reader", "arrayBuffer", "maxSize", "ioNamespace", "u", "t", "delay", "factor", "depth", "reason", "lookup", "c", "splitC", "fullPath", "uibuilder", "selector", "uibuilder", "uib_var_default", "uib_meta_default", "apply_template_default", "uib_control_default", "perf", "_reactiveBindings", "_reactiveObserver", "_experimentalElements", "_activeDialogs", "_dialogCounter", "_templateVariableMap", "_templateDataMap", "_templateStringMap", "_UibExperimental", "Uib", "__privateAdd", "__privateSet", "mutations", "mutation", "node", "__privateGet", "variable", "selector", "config", "bindingId", "bindingConfig", "val", "newValue", "value", "elements", "currentValue", "transformedValue", "element", "event", "attributeName", "root", "resolve", "dialogId", "__privateWrapper", "dialog", "handleClose", "result", "content", "templateElement", "target", "template", "data", "targetElement", "variables", "regex", "match", "rootVar", "existingListeners", "cb", "listener", "storedData", "newContent", "keys", "key", "newData", "autoUpdate", "templateSelector", "processed", "options", "container", "layoutType", "entries", "entry", "width", "minColumnWidth", "columns", "feature", "enabled", "_a", "__publicField", "UibExperimental", "uibExperimental", "experimental_default", "uibExperimental"]
}
