{"version":3,"sources":["../../../../../src/static/js/binder/core/dynamic_frame.js"],"sourcesContent":["import { Controller } from \"../controller.js\";\nimport { parseBoolean, parseDuration } from \"../util.js\";\n\n/*\nThis is the base controller for DynamicFrames\nExtend this and override params() and optionally replaceContent()\n\nThe root HTML node must have a `:url` attribute - this can be relative or absolute\nTo pass params use the attribute format `:param-name`\n\nExample HTML:\n\n*/\n\n/**\n * @class\n * @name DynamicFrame\n * @namespace DynamicFrame\n * @property url - The URL to fetch\n * @property executeScripts - If true will find and execute scripts in the response body\n * @property mode - The mode to use for adding the response content, either `replace`, `append` or `prepend` (Defaults to `replace`)\n * @property mountPoint - A selector used to find the element to mount to within the element (defaults to the root element)\n * @property autoRefresh - Will call `refresh()` automatically at the specified interval (Intervals are in the format `${num}${unit}` where unit is one of ms, s, m, h: `10s` = 10 seconds)\n * @property delay - An artificial delay applied before displaying the content\n * @property stateKey - An optional key, if specified the frame state will be stored and loaded from the page query string\n * @property contained - If `true` then the frame will be self contained, clicking links and submitting forms will be handled within the frame and **not** impact the surrounding page\n * @example\n * \n *
\n *
\n */\nclass DynamicFrame extends Controller {\n /**\n * Setup the DynamicFrame and do the initial request/load\n * @memberof! DynamicFrame\n *\n */\n async init() {\n this.contents = \"\";\n\n // Keep track of pending requests so we can cancel when updating multiple things\n this._reqAbort = [];\n\n this.args.executeScripts = parseBoolean(this.args.executeScripts);\n\n if (this.args.autoRefresh) {\n this.setAutoRefresh();\n }\n\n if (!this.args.delay) this.args.delay = 0;\n\n // If we have a stateKey then track and handle the state\n if (this.args.stateKey) {\n const handleStateChange = () => {\n let frameState = this.loadState();\n\n // Update and refresh\n if (frameState && Object.keys(frameState).length > 0 && this._internal.frameState !== frameState) {\n this.args.url = frameState[`${this.args.stateKey}-url`];\n this._internal.frameState = frameState;\n this.refresh();\n }\n };\n\n // Initial state load\n handleStateChange();\n\n // When the history state changes then reload our state\n // This is triggered when going back and forward in the browser\n window.addEventListener(\"popstate\", () => handleStateChange());\n window.addEventListener(\"pushstate\", () => handleStateChange());\n }\n\n this.containFrame(parseBoolean(this.args.contained));\n\n this.emit(\"dynamic-frame:init\", {});\n if (this.renderOnInit) await this.loadContent();\n }\n\n /**\n * Reload the frame content then call `render()`\n * @memberof! DynamicFrame\n */\n async refresh(method = \"get\") {\n let ok = await this.loadContent(null, method);\n if (ok) await this.render();\n }\n\n /**\n * Call the base `bind()` and re-find the mountPoint in case it's changed\n * @memberof! DynamicFrame\n */\n bind() {\n super.bind();\n\n // Find the mount point\n if (this.args.mountPoint && typeof this.args.mountPoint === \"string\") {\n this.mountPoint = this.querySelector(this.args.mountPoint);\n }\n\n if (!this.mountPoint) {\n this.mountPoint = this.root;\n }\n }\n\n /**\n * Sets an interval to auto call `this.refresh()`\n * Overwrites previously set refresh intervals\n * @memberof! DynamicFrame\n */\n setAutoRefresh() {\n const interval = parseDuration(this.args.autoRefresh);\n\n if (interval === undefined) {\n console.error(`[${this.tag}] Undefined interval passed to setAutoRefresh`);\n return;\n }\n\n if (this._internal.autoRefreshInterval) {\n window.clearInterval(this._internal.autoRefreshInterval);\n }\n\n this._internal.autoRefreshInterval = window.setInterval(() => this.refresh(), interval);\n }\n\n /**\n * [async] Makes a new request and replaces or appends the response to the mountPoint\n * Returns true on success\n * Multiple calls will abort previous requests and return false\n * @returns boolean - true on success\n * @memberof! DynamicFrame\n */\n async loadContent(e, method = \"get\") {\n let url = this.endpoint();\n url.search = new URLSearchParams(this.params());\n\n // Keep track of all pending requests so we can abort them on duplicate calls\n this._reqAbort.forEach(controller => controller.abort());\n this._reqAbort = [];\n\n const abortController = new AbortController();\n this._reqAbort.push(abortController);\n\n let ok = true;\n const sendReq = async () => {\n try {\n let response = await fetch(url, {\n signal: abortController.signal,\n method: method,\n headers: {\n \"X-Dynamic-Frame\": 1,\n },\n });\n\n // If no content then delete self\n if (response.status === 204) {\n this.destroySelf();\n ok = false;\n return;\n }\n\n let text = await response.text();\n this.updateContent(text);\n } catch (err) {\n console.error(err);\n ok = false;\n }\n };\n\n await Promise.allSettled([new Promise(resolve => setTimeout(resolve, this.args.delay)), sendReq()]);\n\n if (ok) {\n this.saveState();\n this.bind(); // The new DOM content might need to be bound to the controller\n }\n\n this.emit(\"dynamic-frame:updated\", {});\n return ok;\n }\n\n /**\n * Actually updates the content\n * This is where the artificial delay is applied\n * @param content - The content to use\n * @param mode - replace or append, defaults to `this.args.mode`\n * @memberof! DynamicFrame\n */\n updateContent(content, mode = null) {\n if (!mode) mode = this.args.mode || \"replace\";\n\n const template = document.createElement(\"template\");\n template.innerHTML = content;\n\n // If we want to execute scripts then go through our template and turn script tags into real scripts\n if (this.args.executeScripts) {\n let scripts = template.content.querySelectorAll(\"script\");\n\n [...scripts].forEach(script => {\n let newScript = document.createElement(\"script\");\n\n // Copy all attributes to the new script\n [...script.attributes].forEach(attr => newScript.setAttribute(attr.name, attr.value));\n\n // Copy the content of the script tag\n if (script.innerHTML) newScript.appendChild(document.createTextNode(script.innerHTML));\n\n // Add the script tag back in\n script.replaceWith(newScript);\n });\n }\n\n if (mode === \"replace\") {\n this.mountPoint.replaceChildren(template.content);\n } else if (mode === \"append\") {\n this.mountPoint.appendChild(template.content);\n } else if (mode === \"prepend\") {\n this.mountPoint.prepend(template.content);\n }\n\n this.emit(\"frame-updated\", { from: this, mode: mode });\n }\n\n /**\n * Returns the query string params for the request - expected to be overridden\n * Handles arrays as duplicated params (ie. a: [1,2] => ?a=1&a=2)\n * @returns {URLSearchParams}\n * @memberof! DynamicFrame\n */\n params(values = {}) {\n let params = new URLSearchParams(values);\n\n // Annoyingly URLSearchParams can't handle array params unless you call .append each time\n // So find any array params and re-add them manually\n Object.entries(values).forEach(([key, val]) => {\n if (Array.isArray(val)) {\n params.delete(key);\n val.forEach(item => params.append(key, item));\n }\n });\n\n for (let attr of this.attributes) {\n if (attr.nodeName.startsWith(\":param-\")) {\n params.append(attr.nodeName.substring(7), attr.nodeValue);\n }\n }\n return params;\n }\n\n /**\n * Set key/value pairs of params in the element attributes\n * @param {object} values\n */\n setParams(values = {}) {\n // Wipe out all current attributes\n for (let attr of this.attributes) {\n if (attr.nodeName.startsWith(\":param-\")) {\n this.removeAttribute(attr.nodeName);\n }\n }\n\n // Set the new params\n Object.entries(values).forEach(([key, val]) => {\n this.setAttribute(`:param-${key}`, val);\n });\n }\n\n /**\n * Returns the endpoint to call - from the :url attr on the root element\n * @returns {string}\n * @memberof! DynamicFrame\n */\n endpoint() {\n let url = this.args.url;\n\n if (!this.args.url) {\n console.error(`${this.tag}: No :url attribute specified`);\n return;\n }\n\n if (!url.startsWith(\"http\")) url = window.location.origin + url;\n return new URL(url);\n }\n\n /**\n * Load the frame state based on the main page URL query string\n * @returns {object} The frame state\n */\n loadState() {\n if (!this.args.stateKey) return;\n\n let qs = window.location.search;\n\n if (!qs) return;\n qs = qs.substring(1);\n let qsParts = Object.fromEntries(qs.split(\"&\").map(part => part.split(\"=\")));\n\n let frameState = {};\n let params = {};\n for (let [key, value] of Object.entries(qsParts)) {\n if (key.startsWith(this.args.stateKey + \"-\")) {\n if (key.startsWith(this.args.stateKey + \"-param-\")) {\n params[key.replace(this.stateKey + \"-param-\", \"\")] = value;\n }\n\n frameState[key] = value;\n }\n }\n\n // Update our params\n this.setParams(params);\n\n return frameState;\n }\n\n /**\n * Loads a URL into the frame by updating the url and param attributes and then reload\n * @param {*} url\n */\n loadUrl(url, method = \"get\") {\n let [origin, query] = url.split(\"?\");\n if (!query) query = \"\";\n\n if (query) {\n const params = Object.fromEntries(query.split(\"&\").map(part => part.split(\"=\")));\n this.setParams(params);\n }\n\n this.args.url = origin;\n this.refresh(method);\n }\n\n /**\n * Save the frame state to the outer page URL query string and add to history\n * Only saves if the state has changed\n */\n saveState() {\n // If no stateKey then we can't save the state\n if (!this.args.stateKey) return;\n\n // Get the main page query string\n let mainPageQs = Object.fromEntries(new URLSearchParams(window.location.search));\n\n // Strip out any params that belong to this frame\n // We will re-add them below\n for (const key of Object.keys(mainPageQs)) {\n if (key.startsWith(`${this.args.stateKey}-`)) {\n delete mainPageQs[key];\n }\n }\n\n // Build our frame state object\n let frameState = {};\n frameState[`${this.args.stateKey}-url`] = this.args.url.replace(window.location.origin, \"\");\n\n // Add the params for this frame\n for (const [key, value] of this.params()) {\n frameState[`${this.args.stateKey}-param-${key}`] = value;\n }\n\n // Merge our frame state into the page params\n mainPageQs = { ...mainPageQs, ...frameState };\n\n // If our state changed then update the main page URL and add to history\n if (this._internal.frameState !== frameState) {\n const qs = Object.entries(mainPageQs)\n .map(part => `${part[0]}=${part[1]}`)\n .join(\"&\");\n\n window.history.pushState(qs, \"\", `?${qs}`);\n this._internal.frameState = frameState;\n }\n }\n\n /**\n * Makes the frame self contained\n * Clicking any links or submitting any forms will only impact the frame, not the surrounding page\n * @param {bool} containAll Whether to automatically contain all `a` and `form` elements\n * If not set then it will be opt in per element.\n */\n containFrame(containAll = false) {\n // Capture all clicks and if it was on an tag load the href within the frame\n this.addEventListener(\"click\", e => {\n let target = e.target || e.srcElement;\n\n if (target.tagName === \"A\" && this.belongsToController(target)) {\n if (!containAll && !target.hasAttribute(\":contained\")) {\n return;\n }\n\n e.preventDefault();\n const href = target.getAttribute(\"href\");\n window.history.pushState({}, \"\", href);\n this.loadUrl(href);\n }\n });\n\n // Intercept form submits\n // To do this we need to submit the form ourselves\n // Aims to have near-full feature parity with regular HTML forms\n // We do not support the `target` attribute or the `method=\"dialog\"` value\n // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form\n this.addEventListener(\"submit\", async e => {\n if (!containAll && !e.target.hasAttribute(\":contained\")) {\n return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n const method = e.target.getAttribute(\"method\") || \"GET\";\n const action = e.target.getAttribute(\"action\") || \"/\";\n const encoding = e.target.getAttribute(\"enctype\") || \"application/x-www-form-urlencoded\";\n const skipValidation = e.target.getAttribute(\"novalidate\") !== undefined;\n\n // Base HTML5 validation\n if (!skipValidation && !e.target.checkValidity()) {\n return;\n }\n\n // Build the form data to send\n const formData = new FormData(e.target);\n let params = new URLSearchParams();\n for (const pair of formData) {\n params.append(pair[0], pair[1]);\n }\n\n if (method.toUpperCase() == \"POST\") {\n let request = {\n method: \"POST\",\n headers: {\n \"X-Dynamic-Frame\": 1,\n },\n };\n\n if (encoding === \"application/x-www-form-urlencoded\") {\n request.body = params;\n request.headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n } else {\n // If sending as multipart then we omit the content-type\n let multipartData = new FormData();\n for (const pair of formData) {\n multipartData.append(pair[0], pair[1]);\n }\n\n request.body = multipartData;\n }\n let response = await fetch(action, request);\n // Show the response body\n this.updateContent(await response.text());\n } else if (method.toUpperCase() == \"GET\") {\n const query = Object.fromEntries(new URLSearchParams(formData));\n this.setParams(query);\n this.args.url = action;\n window.history.pushState({}, \"\", action);\n this.refresh();\n }\n\n return false;\n });\n }\n\n /**\n * Remove self from DOM and remove state from query string\n */\n destroySelf() {\n this.parentElement.removeChild(this);\n\n if (this.args.stateKey) {\n // Get main page query string\n let qs = window.location.search;\n qs = qs.substring(1);\n if (!qs) return;\n\n // Remove any parts that belong to this frame\n let qsParts = Object.fromEntries(qs.split(\"&\").map(part => part.split(\"=\")));\n for (const [key, _value] of Object.entries(qsParts)) {\n if (key.startsWith(this.args.stateKey + \"-\")) {\n delete qsParts[key];\n }\n }\n\n // Back to string and save\n qs = Object.entries(qsParts)\n .map(part => `${part[0]}=${part[1]}`)\n .join(\"&\");\n\n window.history.pushState(qs, \"\", `?${qs}`);\n }\n }\n}\n\n/**\n * Container for route anchor elements\n * Any `` elements within the `` will be intercepted and only update the specified dynamic frame\n * Specifies the target `DynamicFrame` to handle routing for\n */\nclass DynamicFrameRouter extends Controller {\n async init() {\n this.target = document.querySelector(this.args.target);\n this.anchors = this.querySelectorAll(\"a\");\n this.cache = {};\n this.args.caching = parseBoolean(this.args.caching);\n\n if (!this.target) {\n console.error(`Could not find target dynamic frame element: ${this.args.target}`);\n return;\n }\n\n // Handle clicks\n this.addEventListener(\"click\", e => {\n let target = e.target || e.srcElement;\n\n if (target.tagName === \"A\" && this.belongsToController(target)) {\n e.preventDefault();\n this.navigate(target.getAttribute(\"href\"), true);\n }\n });\n\n // Handle history change\n window.onpopstate = history.onpushstate = () => {\n this.navigate(document.location.pathname);\n };\n }\n\n async navigate(href, recordInHistory = false) {\n const targetUrl = new URL(href, window.location.origin);\n const oldHref = this.target.args.url;\n\n // Cache the contents of the frame\n if (this.args.caching) {\n this.cache[oldHref] = [...this.target.children].map(child => child.cloneNode(true));\n }\n\n // Update the targeted frame\n if (href in this.cache) {\n this.target.replaceChildren(...this.cache[href]);\n this.target.args.url = href;\n } else {\n await this.target.loadUrl(href);\n }\n\n // Update the active anchor\n this.anchors.forEach(a => {\n const anchorHref = new URL(a.href);\n\n if (anchorHref.pathname === targetUrl.pathname) {\n a.classList.add(\"active\");\n } else {\n a.classList.remove(\"active\");\n }\n });\n\n if (recordInHistory) window.history.pushState({}, \"\", href);\n }\n}\n\nexport { DynamicFrame, DynamicFrameRouter };\n"],"names":["Controller","parseBoolean","parseDuration","DynamicFrame","init","contents","_reqAbort","args","executeScripts","autoRefresh","setAutoRefresh","delay","stateKey","handleStateChange","frameState","loadState","Object","keys","length","_internal","url","refresh","window","addEventListener","containFrame","contained","emit","renderOnInit","loadContent","method","ok","render","bind","mountPoint","querySelector","root","interval","undefined","console","error","tag","autoRefreshInterval","clearInterval","setInterval","e","endpoint","search","URLSearchParams","params","forEach","controller","abort","abortController","AbortController","push","sendReq","response","fetch","signal","headers","status","destroySelf","text","updateContent","err","Promise","allSettled","resolve","setTimeout","saveState","content","mode","template","document","createElement","innerHTML","scripts","querySelectorAll","script","newScript","attributes","attr","setAttribute","name","value","appendChild","createTextNode","replaceWith","replaceChildren","prepend","from","values","entries","key","val","Array","isArray","delete","item","append","nodeName","startsWith","substring","nodeValue","setParams","removeAttribute","location","origin","URL","qs","qsParts","fromEntries","split","map","part","replace","loadUrl","query","mainPageQs","join","history","pushState","containAll","target","srcElement","tagName","belongsToController","hasAttribute","preventDefault","href","getAttribute","stopPropagation","action","encoding","skipValidation","checkValidity","formData","FormData","pair","toUpperCase","request","body","multipartData","parentElement","removeChild","_value","DynamicFrameRouter","anchors","cache","caching","navigate","onpopstate","onpushstate","pathname","recordInHistory","targetUrl","oldHref","children","child","cloneNode","a","anchorHref","classList","add","remove"],"mappings":"gqCAAA,OAASA,UAAU,KAAQ,kBAAmB,AAC9C,QAASC,YAAY,CAAEC,aAAa,KAAQ,YAAa,AA8BzD,OAAMC,qBAAqBH,WAMvB,AAAMI,6BAAN,oBAAA,YACI,MAAKC,QAAQ,CAAG,EAGhB,OAAKC,SAAS,CAAG,EAAE,AAEnB,OAAKC,IAAI,CAACC,cAAc,CAAGP,aAAa,MAAKM,IAAI,CAACC,cAAc,EAEhE,GAAI,MAAKD,IAAI,CAACE,WAAW,CAAE,CACvB,MAAKC,cAAc,EACvB,CAEA,GAAI,CAAC,MAAKH,IAAI,CAACI,KAAK,CAAE,MAAKJ,IAAI,CAACI,KAAK,CAAG,EAGxC,GAAI,MAAKJ,IAAI,CAACK,QAAQ,CAAE,CACpB,MAAMC,kBAAoB,KACtB,IAAIC,WAAa,MAAKC,SAAS,GAG/B,GAAID,YAAcE,OAAOC,IAAI,CAACH,YAAYI,MAAM,CAAG,GAAK,MAAKC,SAAS,CAACL,UAAU,GAAKA,WAAY,CAC9F,MAAKP,IAAI,CAACa,GAAG,CAAGN,UAAU,CAAC,CAAC,EAAE,MAAKP,IAAI,CAACK,QAAQ,CAAC,IAAI,CAAC,CAAC,AACvD,OAAKO,SAAS,CAACL,UAAU,CAAGA,WAC5B,MAAKO,OAAO,EAChB,CACJ,EAGAR,oBAIAS,OAAOC,gBAAgB,CAAC,WAAY,IAAMV,qBAC1CS,OAAOC,gBAAgB,CAAC,YAAa,IAAMV,oBAC/C,CAEA,MAAKW,YAAY,CAACvB,aAAa,MAAKM,IAAI,CAACkB,SAAS,GAElD,MAAKC,IAAI,CAAC,qBAAsB,CAAC,GACjC,GAAI,MAAKC,YAAY,CAAE,MAAM,MAAKC,WAAW,EACjD,KAMA,AAAMP,QAAQQ,OAAS,KAAK,wBAA5B,oBAAA,YACI,IAAIC,GAAK,MAAM,MAAKF,WAAW,CAAC,KAAMC,QACtC,GAAIC,GAAI,MAAM,MAAKC,MAAM,EAC7B,KAMAC,MAAO,CACH,KAAK,CAACA,OAGN,GAAI,IAAI,CAACzB,IAAI,CAAC0B,UAAU,EAAI,OAAO,IAAI,CAAC1B,IAAI,CAAC0B,UAAU,GAAK,SAAU,CAClE,IAAI,CAACA,UAAU,CAAG,IAAI,CAACC,aAAa,CAAC,IAAI,CAAC3B,IAAI,CAAC0B,UAAU,CAC7D,CAEA,GAAI,CAAC,IAAI,CAACA,UAAU,CAAE,CAClB,IAAI,CAACA,UAAU,CAAG,IAAI,CAACE,IAAI,AAC/B,CACJ,CAOAzB,gBAAiB,CACb,MAAM0B,SAAWlC,cAAc,IAAI,CAACK,IAAI,CAACE,WAAW,EAEpD,GAAI2B,WAAaC,UAAW,CACxBC,QAAQC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAACC,GAAG,CAAC,6CAA6C,CAAC,EACzE,MACJ,CAEA,GAAI,IAAI,CAACrB,SAAS,CAACsB,mBAAmB,CAAE,CACpCnB,OAAOoB,aAAa,CAAC,IAAI,CAACvB,SAAS,CAACsB,mBAAmB,CAC3D,CAEA,IAAI,CAACtB,SAAS,CAACsB,mBAAmB,CAAGnB,OAAOqB,WAAW,CAAC,IAAM,IAAI,CAACtB,OAAO,GAAIe,SAClF,CASA,AAAMR,YAAYgB,CAAC,CAAEf,OAAS,KAAK,wBAAnC,oBAAA,YACI,IAAIT,IAAM,MAAKyB,QAAQ,EACvBzB,CAAAA,IAAI0B,MAAM,CAAG,IAAIC,gBAAgB,MAAKC,MAAM,IAG5C,MAAK1C,SAAS,CAAC2C,OAAO,CAACC,YAAcA,WAAWC,KAAK,GACrD,OAAK7C,SAAS,CAAG,EAAE,CAEnB,MAAM8C,gBAAkB,IAAIC,gBAC5B,MAAK/C,SAAS,CAACgD,IAAI,CAACF,iBAEpB,IAAItB,GAAK,KACT,MAAMyB,4BAAU,oBAAA,YACZ,GAAI,CACA,IAAIC,SAAW,MAAMC,MAAMrC,IAAK,CAC5BsC,OAAQN,gBAAgBM,MAAM,CAC9B7B,OAAQA,OACR8B,QAAS,CACL,kBAAmB,CACvB,CACJ,GAGA,GAAIH,SAASI,MAAM,GAAK,IAAK,CACzB,MAAKC,WAAW,GAChB/B,GAAK,MACL,MACJ,CAEA,IAAIgC,KAAO,MAAMN,SAASM,IAAI,GAC9B,MAAKC,aAAa,CAACD,KACvB,CAAE,MAAOE,IAAK,CACV1B,QAAQC,KAAK,CAACyB,KACdlC,GAAK,KACT,CACJ,mBAvBMyB,+CAyBN,OAAMU,QAAQC,UAAU,CAAC,CAAC,IAAID,QAAQE,SAAWC,WAAWD,QAAS,MAAK5D,IAAI,CAACI,KAAK,GAAI4C,UAAU,EAElG,GAAIzB,GAAI,CACJ,MAAKuC,SAAS,GACd,MAAKrC,IAAI,EACb,CAEA,MAAKN,IAAI,CAAC,wBAAyB,CAAC,GACpC,OAAOI,EACX,KASAiC,cAAcO,OAAO,CAAEC,KAAO,IAAI,CAAE,CAChC,GAAI,CAACA,KAAMA,KAAO,IAAI,CAAChE,IAAI,CAACgE,IAAI,EAAI,UAEpC,MAAMC,SAAWC,SAASC,aAAa,CAAC,WACxCF,CAAAA,SAASG,SAAS,CAAGL,QAGrB,GAAI,IAAI,CAAC/D,IAAI,CAACC,cAAc,CAAE,CAC1B,IAAIoE,QAAUJ,SAASF,OAAO,CAACO,gBAAgB,CAAC,UAEhD,IAAID,QAAQ,CAAC3B,OAAO,CAAC6B,SACjB,IAAIC,UAAYN,SAASC,aAAa,CAAC,UAGvC,IAAII,OAAOE,UAAU,CAAC,CAAC/B,OAAO,CAACgC,MAAQF,UAAUG,YAAY,CAACD,KAAKE,IAAI,CAAEF,KAAKG,KAAK,GAGnF,GAAIN,OAAOH,SAAS,CAAEI,UAAUM,WAAW,CAACZ,SAASa,cAAc,CAACR,OAAOH,SAAS,GAGpFG,OAAOS,WAAW,CAACR,UACvB,EACJ,CAEA,GAAIR,OAAS,UAAW,CACpB,IAAI,CAACtC,UAAU,CAACuD,eAAe,CAAChB,SAASF,OAAO,CACpD,MAAO,GAAIC,OAAS,SAAU,CAC1B,IAAI,CAACtC,UAAU,CAACoD,WAAW,CAACb,SAASF,OAAO,CAChD,MAAO,GAAIC,OAAS,UAAW,CAC3B,IAAI,CAACtC,UAAU,CAACwD,OAAO,CAACjB,SAASF,OAAO,CAC5C,CAEA,IAAI,CAAC5C,IAAI,CAAC,gBAAiB,CAAEgE,KAAM,IAAI,CAAEnB,KAAMA,IAAK,EACxD,CAQAvB,OAAO2C,OAAS,CAAC,CAAC,CAAE,CAChB,IAAI3C,OAAS,IAAID,gBAAgB4C,QAIjC3E,OAAO4E,OAAO,CAACD,QAAQ1C,OAAO,CAAC,CAAC,CAAC4C,IAAKC,IAAI,IACtC,GAAIC,MAAMC,OAAO,CAACF,KAAM,CACpB9C,OAAOiD,MAAM,CAACJ,KACdC,IAAI7C,OAAO,CAACiD,MAAQlD,OAAOmD,MAAM,CAACN,IAAKK,MAC3C,CACJ,GAEA,IAAK,IAAIjB,QAAQ,IAAI,CAACD,UAAU,CAAE,CAC9B,GAAIC,KAAKmB,QAAQ,CAACC,UAAU,CAAC,WAAY,CACrCrD,OAAOmD,MAAM,CAAClB,KAAKmB,QAAQ,CAACE,SAAS,CAAC,GAAIrB,KAAKsB,SAAS,CAC5D,CACJ,CACA,OAAOvD,MACX,CAMAwD,UAAUb,OAAS,CAAC,CAAC,CAAE,CAEnB,IAAK,IAAIV,QAAQ,IAAI,CAACD,UAAU,CAAE,CAC9B,GAAIC,KAAKmB,QAAQ,CAACC,UAAU,CAAC,WAAY,CACrC,IAAI,CAACI,eAAe,CAACxB,KAAKmB,QAAQ,CACtC,CACJ,CAGApF,OAAO4E,OAAO,CAACD,QAAQ1C,OAAO,CAAC,CAAC,CAAC4C,IAAKC,IAAI,IACtC,IAAI,CAACZ,YAAY,CAAC,CAAC,OAAO,EAAEW,IAAI,CAAC,CAAEC,IACvC,EACJ,CAOAjD,UAAW,CACP,IAAIzB,IAAM,IAAI,CAACb,IAAI,CAACa,GAAG,CAEvB,GAAI,CAAC,IAAI,CAACb,IAAI,CAACa,GAAG,CAAE,CAChBkB,QAAQC,KAAK,CAAC,CAAC,EAAE,IAAI,CAACC,GAAG,CAAC,6BAA6B,CAAC,EACxD,MACJ,CAEA,GAAI,CAACpB,IAAIiF,UAAU,CAAC,QAASjF,IAAME,OAAOoF,QAAQ,CAACC,MAAM,CAAGvF,IAC5D,OAAO,IAAIwF,IAAIxF,IACnB,CAMAL,WAAY,CACR,GAAI,CAAC,IAAI,CAACR,IAAI,CAACK,QAAQ,CAAE,OAEzB,IAAIiG,GAAKvF,OAAOoF,QAAQ,CAAC5D,MAAM,CAE/B,GAAI,CAAC+D,GAAI,OACTA,GAAKA,GAAGP,SAAS,CAAC,GAClB,IAAIQ,QAAU9F,OAAO+F,WAAW,CAACF,GAAGG,KAAK,CAAC,KAAKC,GAAG,CAACC,MAAQA,KAAKF,KAAK,CAAC,OAEtE,IAAIlG,WAAa,CAAC,EAClB,IAAIkC,OAAS,CAAC,EACd,IAAK,GAAI,CAAC6C,IAAKT,MAAM,GAAIpE,OAAO4E,OAAO,CAACkB,SAAU,CAC9C,GAAIjB,IAAIQ,UAAU,CAAC,IAAI,CAAC9F,IAAI,CAACK,QAAQ,CAAG,KAAM,CAC1C,GAAIiF,IAAIQ,UAAU,CAAC,IAAI,CAAC9F,IAAI,CAACK,QAAQ,CAAG,WAAY,CAChDoC,MAAM,CAAC6C,IAAIsB,OAAO,CAAC,IAAI,CAACvG,QAAQ,CAAG,UAAW,IAAI,CAAGwE,KACzD,CAEAtE,UAAU,CAAC+E,IAAI,CAAGT,KACtB,CACJ,CAGA,IAAI,CAACoB,SAAS,CAACxD,QAEf,OAAOlC,UACX,CAMAsG,QAAQhG,GAAG,CAAES,OAAS,KAAK,CAAE,CACzB,GAAI,CAAC8E,OAAQU,MAAM,CAAGjG,IAAI4F,KAAK,CAAC,KAChC,GAAI,CAACK,MAAOA,MAAQ,GAEpB,GAAIA,MAAO,CACP,MAAMrE,OAAShC,OAAO+F,WAAW,CAACM,MAAML,KAAK,CAAC,KAAKC,GAAG,CAACC,MAAQA,KAAKF,KAAK,CAAC,OAC1E,IAAI,CAACR,SAAS,CAACxD,OACnB,CAEA,IAAI,CAACzC,IAAI,CAACa,GAAG,CAAGuF,OAChB,IAAI,CAACtF,OAAO,CAACQ,OACjB,CAMAwC,WAAY,CAER,GAAI,CAAC,IAAI,CAAC9D,IAAI,CAACK,QAAQ,CAAE,OAGzB,IAAI0G,WAAatG,OAAO+F,WAAW,CAAC,IAAIhE,gBAAgBzB,OAAOoF,QAAQ,CAAC5D,MAAM,GAI9E,IAAK,MAAM+C,OAAO7E,OAAOC,IAAI,CAACqG,YAAa,CACvC,GAAIzB,IAAIQ,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC9F,IAAI,CAACK,QAAQ,CAAC,CAAC,CAAC,EAAG,CAC1C,OAAO0G,UAAU,CAACzB,IAAI,AAC1B,CACJ,CAGA,IAAI/E,WAAa,CAAC,CAClBA,CAAAA,UAAU,CAAC,CAAC,EAAE,IAAI,CAACP,IAAI,CAACK,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAG,IAAI,CAACL,IAAI,CAACa,GAAG,CAAC+F,OAAO,CAAC7F,OAAOoF,QAAQ,CAACC,MAAM,CAAE,IAGxF,IAAK,KAAM,CAACd,IAAKT,MAAM,GAAI,IAAI,CAACpC,MAAM,GAAI,CACtClC,UAAU,CAAC,CAAC,EAAE,IAAI,CAACP,IAAI,CAACK,QAAQ,CAAC,OAAO,EAAEiF,IAAI,CAAC,CAAC,CAAGT,KACvD,CAGAkC,WAAa,kBAAKA,WAAexG,YAGjC,GAAI,IAAI,CAACK,SAAS,CAACL,UAAU,GAAKA,WAAY,CAC1C,MAAM+F,GAAK7F,OAAO4E,OAAO,CAAC0B,YACrBL,GAAG,CAACC,MAAQ,CAAC,EAAEA,IAAI,CAAC,EAAE,CAAC,CAAC,EAAEA,IAAI,CAAC,EAAE,CAAC,CAAC,EACnCK,IAAI,CAAC,KAEVjG,OAAOkG,OAAO,CAACC,SAAS,CAACZ,GAAI,GAAI,CAAC,CAAC,EAAEA,GAAG,CAAC,CACzC,CAAA,IAAI,CAAC1F,SAAS,CAACL,UAAU,CAAGA,UAChC,CACJ,CAQAU,aAAakG,WAAa,KAAK,CAAE,CAE7B,IAAI,CAACnG,gBAAgB,CAAC,QAASqB,IAC3B,IAAI+E,OAAS/E,EAAE+E,MAAM,EAAI/E,EAAEgF,UAAU,CAErC,GAAID,OAAOE,OAAO,GAAK,KAAO,IAAI,CAACC,mBAAmB,CAACH,QAAS,CAC5D,GAAI,CAACD,YAAc,CAACC,OAAOI,YAAY,CAAC,cAAe,CACnD,MACJ,CAEAnF,EAAEoF,cAAc,GAChB,MAAMC,KAAON,OAAOO,YAAY,CAAC,QACjC5G,OAAOkG,OAAO,CAACC,SAAS,CAAC,CAAC,EAAG,GAAIQ,MACjC,IAAI,CAACb,OAAO,CAACa,KACjB,CACJ,kBAOA,IAAI,CAAC1G,gBAAgB,CAAC,6BAAU,oBAAA,UAAMqB,GAClC,GAAI,CAAC8E,YAAc,CAAC9E,EAAE+E,MAAM,CAACI,YAAY,CAAC,cAAe,CACrD,MACJ,CAEAnF,EAAEoF,cAAc,GAChBpF,EAAEuF,eAAe,GAEjB,MAAMtG,OAASe,EAAE+E,MAAM,CAACO,YAAY,CAAC,WAAa,MAClD,MAAME,OAASxF,EAAE+E,MAAM,CAACO,YAAY,CAAC,WAAa,IAClD,MAAMG,SAAWzF,EAAE+E,MAAM,CAACO,YAAY,CAAC,YAAc,oCACrD,MAAMI,eAAiB1F,EAAE+E,MAAM,CAACO,YAAY,CAAC,gBAAkB7F,UAG/D,GAAI,CAACiG,gBAAkB,CAAC1F,EAAE+E,MAAM,CAACY,aAAa,GAAI,CAC9C,MACJ,CAGA,MAAMC,SAAW,IAAIC,SAAS7F,EAAE+E,MAAM,EACtC,IAAI3E,OAAS,IAAID,gBACjB,IAAK,MAAM2F,QAAQF,SAAU,CACzBxF,OAAOmD,MAAM,CAACuC,IAAI,CAAC,EAAE,CAAEA,IAAI,CAAC,EAAE,CAClC,CAEA,GAAI7G,OAAO8G,WAAW,IAAM,OAAQ,CAChC,IAAIC,QAAU,CACV/G,OAAQ,OACR8B,QAAS,CACL,kBAAmB,CACvB,CACJ,EAEA,GAAI0E,WAAa,oCAAqC,CAClDO,QAAQC,IAAI,CAAG7F,MACf4F,CAAAA,QAAQjF,OAAO,CAAC,eAAe,CAAG,mCACtC,KAAO,CAEH,IAAImF,cAAgB,IAAIL,SACxB,IAAK,MAAMC,QAAQF,SAAU,CACzBM,cAAc3C,MAAM,CAACuC,IAAI,CAAC,EAAE,CAAEA,IAAI,CAAC,EAAE,CACzC,CAEAE,QAAQC,IAAI,CAAGC,aACnB,CACA,IAAItF,SAAW,MAAMC,MAAM2E,OAAQQ,SAEnC,MAAK7E,aAAa,CAAC,CAAA,MAAMP,SAASM,IAAI,EAAC,EAC3C,MAAO,GAAIjC,OAAO8G,WAAW,IAAM,MAAO,CACtC,MAAMtB,MAAQrG,OAAO+F,WAAW,CAAC,IAAIhE,gBAAgByF,WACrD,MAAKhC,SAAS,CAACa,MACf,OAAK9G,IAAI,CAACa,GAAG,CAAGgH,OAChB9G,OAAOkG,OAAO,CAACC,SAAS,CAAC,CAAC,EAAG,GAAIW,QACjC,MAAK/G,OAAO,EAChB,CAEA,OAAO,KACX,mBAzDsCuB,yCA0D1C,CAKAiB,aAAc,CACV,IAAI,CAACkF,aAAa,CAACC,WAAW,CAAC,IAAI,EAEnC,GAAI,IAAI,CAACzI,IAAI,CAACK,QAAQ,CAAE,CAEpB,IAAIiG,GAAKvF,OAAOoF,QAAQ,CAAC5D,MAAM,CAC/B+D,GAAKA,GAAGP,SAAS,CAAC,GAClB,GAAI,CAACO,GAAI,OAGT,IAAIC,QAAU9F,OAAO+F,WAAW,CAACF,GAAGG,KAAK,CAAC,KAAKC,GAAG,CAACC,MAAQA,KAAKF,KAAK,CAAC,OACtE,IAAK,KAAM,CAACnB,IAAKoD,OAAO,GAAIjI,OAAO4E,OAAO,CAACkB,SAAU,CACjD,GAAIjB,IAAIQ,UAAU,CAAC,IAAI,CAAC9F,IAAI,CAACK,QAAQ,CAAG,KAAM,CAC1C,OAAOkG,OAAO,CAACjB,IAAI,AACvB,CACJ,CAGAgB,GAAK7F,OAAO4E,OAAO,CAACkB,SACfG,GAAG,CAACC,MAAQ,CAAC,EAAEA,IAAI,CAAC,EAAE,CAAC,CAAC,EAAEA,IAAI,CAAC,EAAE,CAAC,CAAC,EACnCK,IAAI,CAAC,KAEVjG,OAAOkG,OAAO,CAACC,SAAS,CAACZ,GAAI,GAAI,CAAC,CAAC,EAAEA,GAAG,CAAC,CAC7C,CACJ,CACJ,CAOA,MAAMqC,2BAA2BlJ,WAC7B,AAAMI,6BAAN,oBAAA,YACI,MAAKuH,MAAM,CAAGlD,SAASvC,aAAa,CAAC,MAAK3B,IAAI,CAACoH,MAAM,CACrD,OAAKwB,OAAO,CAAG,MAAKtE,gBAAgB,CAAC,IACrC,OAAKuE,KAAK,CAAG,CAAC,CACd,OAAK7I,IAAI,CAAC8I,OAAO,CAAGpJ,aAAa,MAAKM,IAAI,CAAC8I,OAAO,EAElD,GAAI,CAAC,MAAK1B,MAAM,CAAE,CACdrF,QAAQC,KAAK,CAAC,CAAC,6CAA6C,EAAE,MAAKhC,IAAI,CAACoH,MAAM,CAAC,CAAC,EAChF,MACJ,CAGA,MAAKpG,gBAAgB,CAAC,QAASqB,IAC3B,IAAI+E,OAAS/E,EAAE+E,MAAM,EAAI/E,EAAEgF,UAAU,CAErC,GAAID,OAAOE,OAAO,GAAK,KAAO,MAAKC,mBAAmB,CAACH,QAAS,CAC5D/E,EAAEoF,cAAc,GAChB,MAAKsB,QAAQ,CAAC3B,OAAOO,YAAY,CAAC,QAAS,KAC/C,CACJ,EAGA5G,CAAAA,OAAOiI,UAAU,CAAG/B,QAAQgC,WAAW,CAAG,KACtC,MAAKF,QAAQ,CAAC7E,SAASiC,QAAQ,CAAC+C,QAAQ,CAC5C,CACJ,KAEA,AAAMH,SAASrB,IAAI,CAAEyB,gBAAkB,KAAK,wBAA5C,oBAAA,YACI,MAAMC,UAAY,IAAI/C,IAAIqB,KAAM3G,OAAOoF,QAAQ,CAACC,MAAM,EACtD,MAAMiD,QAAU,MAAKjC,MAAM,CAACpH,IAAI,CAACa,GAAG,CAGpC,GAAI,MAAKb,IAAI,CAAC8I,OAAO,CAAE,CACnB,MAAKD,KAAK,CAACQ,QAAQ,CAAG,IAAI,MAAKjC,MAAM,CAACkC,QAAQ,CAAC,CAAC5C,GAAG,CAAC6C,OAASA,MAAMC,SAAS,CAAC,MACjF,CAGA,GAAI9B,QAAQ,MAAKmB,KAAK,CAAE,CACpB,MAAKzB,MAAM,CAACnC,eAAe,IAAI,MAAK4D,KAAK,CAACnB,KAAK,CAC/C,OAAKN,MAAM,CAACpH,IAAI,CAACa,GAAG,CAAG6G,IAC3B,KAAO,CACH,MAAM,MAAKN,MAAM,CAACP,OAAO,CAACa,KAC9B,CAGA,MAAKkB,OAAO,CAAClG,OAAO,CAAC+G,IACjB,MAAMC,WAAa,IAAIrD,IAAIoD,EAAE/B,IAAI,EAEjC,GAAIgC,WAAWR,QAAQ,GAAKE,UAAUF,QAAQ,CAAE,CAC5CO,EAAEE,SAAS,CAACC,GAAG,CAAC,SACpB,KAAO,CACHH,EAAEE,SAAS,CAACE,MAAM,CAAC,SACvB,CACJ,GAEA,GAAIV,gBAAiBpI,OAAOkG,OAAO,CAACC,SAAS,CAAC,CAAC,EAAG,GAAIQ,KAC1D,KACJ,CAEA,OAAS9H,YAAY,CAAE+I,kBAAkB,CAAG"}