phoenix_live_view 0.17.13 → 0.17.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/package.json +1 -1
- package/package.json +1 -1
- package/priv/static/phoenix_live_view.cjs.js +1 -1
- package/priv/static/phoenix_live_view.cjs.js.map +1 -1
- package/priv/static/phoenix_live_view.esm.js +1 -1
- package/priv/static/phoenix_live_view.esm.js.map +1 -1
- package/priv/static/phoenix_live_view.js +1 -1
- package/priv/static/phoenix_live_view.min.js +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../assets/js/phoenix_live_view/index.js", "../../assets/js/phoenix_live_view/constants.js", "../../assets/js/phoenix_live_view/entry_uploader.js", "../../assets/js/phoenix_live_view/utils.js", "../../assets/js/phoenix_live_view/browser.js", "../../assets/js/phoenix_live_view/dom.js", "../../assets/js/phoenix_live_view/upload_entry.js", "../../assets/js/phoenix_live_view/live_uploader.js", "../../assets/js/phoenix_live_view/hooks.js", "../../assets/js/phoenix_live_view/dom_post_morph_restorer.js", "../../assets/node_modules/morphdom/dist/morphdom-esm.js", "../../assets/js/phoenix_live_view/dom_patch.js", "../../assets/js/phoenix_live_view/rendered.js", "../../assets/js/phoenix_live_view/view_hook.js", "../../assets/js/phoenix_live_view/js.js", "../../assets/js/phoenix_live_view/view.js", "../../assets/js/phoenix_live_view/live_socket.js"],
|
|
4
|
-
"sourcesContent": ["/*\n================================================================================\nPhoenix LiveView JavaScript Client\n================================================================================\n\nSee the hexdocs at `https://hexdocs.pm/phoenix_live_view` for documentation.\n\n*/\n\nimport LiveSocket from \"./live_socket\"\nexport {\n LiveSocket\n}\n", "\nexport const CONSECUTIVE_RELOADS = \"consecutive-reloads\"\nexport const MAX_RELOADS = 10\nexport const RELOAD_JITTER_MIN = 5000\nexport const RELOAD_JITTER_MAX = 10000\nexport const FAILSAFE_JITTER = 30000\nexport const PHX_EVENT_CLASSES = [\n \"phx-click-loading\", \"phx-change-loading\", \"phx-submit-loading\",\n \"phx-keydown-loading\", \"phx-keyup-loading\", \"phx-blur-loading\", \"phx-focus-loading\"\n]\nexport const PHX_COMPONENT = \"data-phx-component\"\nexport const PHX_LIVE_LINK = \"data-phx-link\"\nexport const PHX_TRACK_STATIC = \"track-static\"\nexport const PHX_LINK_STATE = \"data-phx-link-state\"\nexport const PHX_REF = \"data-phx-ref\"\nexport const PHX_REF_SRC = \"data-phx-ref-src\"\nexport const PHX_TRACK_UPLOADS = \"track-uploads\"\nexport const PHX_UPLOAD_REF = \"data-phx-upload-ref\"\nexport const PHX_PREFLIGHTED_REFS = \"data-phx-preflighted-refs\"\nexport const PHX_DONE_REFS = \"data-phx-done-refs\"\nexport const PHX_DROP_TARGET = \"drop-target\"\nexport const PHX_ACTIVE_ENTRY_REFS = \"data-phx-active-refs\"\nexport const PHX_LIVE_FILE_UPDATED = \"phx:live-file:updated\"\nexport const PHX_SKIP = \"data-phx-skip\"\nexport const PHX_PRUNE = \"data-phx-prune\"\nexport const PHX_PAGE_LOADING = \"page-loading\"\nexport const PHX_CONNECTED_CLASS = \"phx-connected\"\nexport const PHX_DISCONNECTED_CLASS = \"phx-loading\"\nexport const PHX_NO_FEEDBACK_CLASS = \"phx-no-feedback\"\nexport const PHX_ERROR_CLASS = \"phx-error\"\nexport const PHX_PARENT_ID = \"data-phx-parent-id\"\nexport const PHX_MAIN = \"data-phx-main\"\nexport const PHX_ROOT_ID = \"data-phx-root-id\"\nexport const PHX_TRIGGER_ACTION = \"trigger-action\"\nexport const PHX_FEEDBACK_FOR = \"feedback-for\"\nexport const PHX_HAS_FOCUSED = \"phx-has-focused\"\nexport const FOCUSABLE_INPUTS = [\"text\", \"textarea\", \"number\", \"email\", \"password\", \"search\", \"tel\", \"url\", \"date\", \"time\", \"datetime-local\", \"color\", \"range\"]\nexport const CHECKABLE_INPUTS = [\"checkbox\", \"radio\"]\nexport const PHX_HAS_SUBMITTED = \"phx-has-submitted\"\nexport const PHX_SESSION = \"data-phx-session\"\nexport const PHX_VIEW_SELECTOR = `[${PHX_SESSION}]`\nexport const PHX_STICKY = \"data-phx-sticky\"\nexport const PHX_STATIC = \"data-phx-static\"\nexport const PHX_READONLY = \"data-phx-readonly\"\nexport const PHX_DISABLED = \"data-phx-disabled\"\nexport const PHX_DISABLE_WITH = \"disable-with\"\nexport const PHX_DISABLE_WITH_RESTORE = \"data-phx-disable-with-restore\"\nexport const PHX_HOOK = \"hook\"\nexport const PHX_DEBOUNCE = \"debounce\"\nexport const PHX_THROTTLE = \"throttle\"\nexport const PHX_UPDATE = \"update\"\nexport const PHX_KEY = \"key\"\nexport const PHX_PRIVATE = \"phxPrivate\"\nexport const PHX_AUTO_RECOVER = \"auto-recover\"\nexport const PHX_LV_DEBUG = \"phx:live-socket:debug\"\nexport const PHX_LV_PROFILE = \"phx:live-socket:profiling\"\nexport const PHX_LV_LATENCY_SIM = \"phx:live-socket:latency-sim\"\nexport const PHX_PROGRESS = \"progress\"\nexport const LOADER_TIMEOUT = 1\nexport const BEFORE_UNLOAD_LOADER_TIMEOUT = 200\nexport const BINDING_PREFIX = \"phx-\"\nexport const PUSH_TIMEOUT = 30000\nexport const LINK_HEADER = \"x-requested-with\"\nexport const RESPONSE_URL_HEADER = \"x-response-url\"\nexport const DEBOUNCE_TRIGGER = \"debounce-trigger\"\nexport const THROTTLED = \"throttled\"\nexport const DEBOUNCE_PREV_KEY = \"debounce-prev-key\"\nexport const DEFAULTS = {\n debounce: 300,\n throttle: 300\n}\n\n// Rendered\nexport const DYNAMICS = \"d\"\nexport const STATIC = \"s\"\nexport const COMPONENTS = \"c\"\nexport const EVENTS = \"e\"\nexport const REPLY = \"r\"\nexport const TITLE = \"t\"\nexport const TEMPLATES = \"p\"\n", "import {\n logError\n} from \"./utils\"\n\nexport default class EntryUploader {\n constructor(entry, chunkSize, liveSocket){\n this.liveSocket = liveSocket\n this.entry = entry\n this.offset = 0\n this.chunkSize = chunkSize\n this.chunkTimer = null\n this.uploadChannel = liveSocket.channel(`lvu:${entry.ref}`, {token: entry.metadata()})\n }\n\n error(reason){\n clearTimeout(this.chunkTimer)\n this.uploadChannel.leave()\n this.entry.error(reason)\n }\n\n upload(){\n this.uploadChannel.onError(reason => this.error(reason))\n this.uploadChannel.join()\n .receive(\"ok\", _data => this.readNextChunk())\n .receive(\"error\", reason => this.error(reason))\n }\n\n isDone(){ return this.offset >= this.entry.file.size }\n\n readNextChunk(){\n let reader = new window.FileReader()\n let blob = this.entry.file.slice(this.offset, this.chunkSize + this.offset)\n reader.onload = (e) => {\n if(e.target.error === null){\n this.offset += e.target.result.byteLength\n this.pushChunk(e.target.result)\n } else {\n return logError(\"Read error: \" + e.target.error)\n }\n }\n reader.readAsArrayBuffer(blob)\n }\n\n pushChunk(chunk){\n if(!this.uploadChannel.isJoined()){ return }\n this.uploadChannel.push(\"chunk\", chunk)\n .receive(\"ok\", () => {\n this.entry.progress((this.offset / this.entry.file.size) * 100)\n if(!this.isDone()){\n this.chunkTimer = setTimeout(() => this.readNextChunk(), this.liveSocket.getLatencySim() || 0)\n }\n })\n }\n}\n", "import {\n PHX_VIEW_SELECTOR\n} from \"./constants\"\n\nimport EntryUploader from \"./entry_uploader\"\n\nexport let logError = (msg, obj) => console.error && console.error(msg, obj)\n\nexport let isCid = (cid) => {\n let type = typeof(cid)\n return type === \"number\" || (type === \"string\" && /^(0|[1-9]\\d*)$/.test(cid))\n}\n\nexport function detectDuplicateIds(){\n let ids = new Set()\n let elems = document.querySelectorAll(\"*[id]\")\n for(let i = 0, len = elems.length; i < len; i++){\n if(ids.has(elems[i].id)){\n console.error(`Multiple IDs detected: ${elems[i].id}. Ensure unique element ids.`)\n } else {\n ids.add(elems[i].id)\n }\n }\n}\n\nexport let debug = (view, kind, msg, obj) => {\n if(view.liveSocket.isDebugEnabled()){\n console.log(`${view.id} ${kind}: ${msg} - `, obj)\n }\n}\n\n// wraps value in closure or returns closure\nexport let closure = (val) => typeof val === \"function\" ? val : function (){ return val }\n\nexport let clone = (obj) => { return JSON.parse(JSON.stringify(obj)) }\n\nexport let closestPhxBinding = (el, binding, borderEl) => {\n do {\n if(el.matches(`[${binding}]`)){ return el }\n el = el.parentElement || el.parentNode\n } while(el !== null && el.nodeType === 1 && !((borderEl && borderEl.isSameNode(el)) || el.matches(PHX_VIEW_SELECTOR)))\n return null\n}\n\nexport let isObject = (obj) => {\n return obj !== null && typeof obj === \"object\" && !(obj instanceof Array)\n}\n\nexport let isEqualObj = (obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2)\n\nexport let isEmpty = (obj) => {\n for(let x in obj){ return false }\n return true\n}\n\nexport let maybe = (el, callback) => el && callback(el)\n\nexport let channelUploader = function (entries, onError, resp, liveSocket){\n entries.forEach(entry => {\n let entryUploader = new EntryUploader(entry, resp.config.chunk_size, liveSocket)\n entryUploader.upload()\n })\n}\n", "let Browser = {\n canPushState(){ return (typeof (history.pushState) !== \"undefined\") },\n\n dropLocal(localStorage, namespace, subkey){\n return localStorage.removeItem(this.localKey(namespace, subkey))\n },\n\n updateLocal(localStorage, namespace, subkey, initial, func){\n let current = this.getLocal(localStorage, namespace, subkey)\n let key = this.localKey(namespace, subkey)\n let newVal = current === null ? initial : func(current)\n localStorage.setItem(key, JSON.stringify(newVal))\n return newVal\n },\n\n getLocal(localStorage, namespace, subkey){\n return JSON.parse(localStorage.getItem(this.localKey(namespace, subkey)))\n },\n\n updateCurrentState(callback){\n if(!this.canPushState()){ return }\n history.replaceState(callback(history.state || {}), \"\", window.location.href)\n },\n\n pushState(kind, meta, to){\n if(this.canPushState()){\n if(to !== window.location.href){\n if(meta.type == \"redirect\" && meta.scroll){\n // If we're redirecting store the current scrollY for the current history state.\n let currentState = history.state || {}\n currentState.scroll = meta.scroll\n history.replaceState(currentState, \"\", window.location.href)\n }\n\n delete meta.scroll // Only store the scroll in the redirect case.\n history[kind + \"State\"](meta, \"\", to || null) // IE will coerce undefined to string\n let hashEl = this.getHashTargetEl(window.location.hash)\n\n if(hashEl){\n hashEl.scrollIntoView()\n } else if(meta.type === \"redirect\"){\n window.scroll(0, 0)\n }\n }\n } else {\n this.redirect(to)\n }\n },\n\n setCookie(name, value){\n document.cookie = `${name}=${value}`\n },\n\n getCookie(name){\n return document.cookie.replace(new RegExp(`(?:(?:^|.*;\\s*)${name}\\s*\\=\\s*([^;]*).*$)|^.*$`), \"$1\")\n },\n\n redirect(toURL, flash){\n if(flash){ Browser.setCookie(\"__phoenix_flash__\", flash + \"; max-age=60000; path=/\") }\n window.location = toURL\n },\n\n localKey(namespace, subkey){ return `${namespace}-${subkey}` },\n\n getHashTargetEl(maybeHash){\n let hash = maybeHash.toString().substring(1)\n if(hash === \"\"){ return }\n return document.getElementById(hash) || document.querySelector(`a[name=\"${hash}\"]`)\n }\n}\n\nexport default Browser\n", "import {\n CHECKABLE_INPUTS,\n DEBOUNCE_PREV_KEY,\n DEBOUNCE_TRIGGER,\n FOCUSABLE_INPUTS,\n PHX_COMPONENT,\n PHX_EVENT_CLASSES,\n PHX_HAS_FOCUSED,\n PHX_HAS_SUBMITTED,\n PHX_MAIN,\n PHX_NO_FEEDBACK_CLASS,\n PHX_PARENT_ID,\n PHX_PRIVATE,\n PHX_REF,\n PHX_REF_SRC,\n PHX_ROOT_ID,\n PHX_SESSION,\n PHX_STATIC,\n PHX_UPLOAD_REF,\n PHX_VIEW_SELECTOR,\n PHX_STICKY,\n THROTTLED\n} from \"./constants\"\n\nimport {\n logError\n} from \"./utils\"\n\nlet DOM = {\n byId(id){ return document.getElementById(id) || logError(`no id found for ${id}`) },\n\n removeClass(el, className){\n el.classList.remove(className)\n if(el.classList.length === 0){ el.removeAttribute(\"class\") }\n },\n\n all(node, query, callback){\n if(!node){ return [] }\n let array = Array.from(node.querySelectorAll(query))\n return callback ? array.forEach(callback) : array\n },\n\n childNodeLength(html){\n let template = document.createElement(\"template\")\n template.innerHTML = html\n return template.content.childElementCount\n },\n\n isUploadInput(el){ return el.type === \"file\" && el.getAttribute(PHX_UPLOAD_REF) !== null },\n\n findUploadInputs(node){ return this.all(node, `input[type=\"file\"][${PHX_UPLOAD_REF}]`) },\n\n findComponentNodeList(node, cid){\n return this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}=\"${cid}\"]`), node)\n },\n\n isPhxDestroyed(node){\n return node.id && DOM.private(node, \"destroyed\") ? true : false\n },\n\n markPhxChildDestroyed(el){\n if(this.isPhxChild(el)){ el.setAttribute(PHX_SESSION, \"\") }\n this.putPrivate(el, \"destroyed\", true)\n },\n\n findPhxChildrenInFragment(html, parentId){\n let template = document.createElement(\"template\")\n template.innerHTML = html\n return this.findPhxChildren(template.content, parentId)\n },\n\n isIgnored(el, phxUpdate){\n return (el.getAttribute(phxUpdate) || el.getAttribute(\"data-phx-update\")) === \"ignore\"\n },\n\n isPhxUpdate(el, phxUpdate, updateTypes){\n return el.getAttribute && updateTypes.indexOf(el.getAttribute(phxUpdate)) >= 0\n },\n\n findPhxSticky(el){ return this.all(el, `[${PHX_STICKY}]`) },\n\n findPhxChildren(el, parentId){\n return this.all(el, `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}=\"${parentId}\"]`)\n },\n\n findParentCIDs(node, cids){\n let initial = new Set(cids)\n return cids.reduce((acc, cid) => {\n let selector = `[${PHX_COMPONENT}=\"${cid}\"] [${PHX_COMPONENT}]`\n\n this.filterWithinSameLiveView(this.all(node, selector), node)\n .map(el => parseInt(el.getAttribute(PHX_COMPONENT)))\n .forEach(childCID => acc.delete(childCID))\n\n return acc\n }, initial)\n },\n\n filterWithinSameLiveView(nodes, parent){\n if(parent.querySelector(PHX_VIEW_SELECTOR)){\n return nodes.filter(el => this.withinSameLiveView(el, parent))\n } else {\n return nodes\n }\n },\n\n withinSameLiveView(node, parent){\n while(node = node.parentNode){\n if(node.isSameNode(parent)){ return true }\n if(node.getAttribute(PHX_SESSION) !== null){ return false }\n }\n },\n\n private(el, key){ return el[PHX_PRIVATE] && el[PHX_PRIVATE][key] },\n\n deletePrivate(el, key){ el[PHX_PRIVATE] && delete (el[PHX_PRIVATE][key]) },\n\n putPrivate(el, key, value){\n if(!el[PHX_PRIVATE]){ el[PHX_PRIVATE] = {} }\n el[PHX_PRIVATE][key] = value\n },\n\n updatePrivate(el, key, defaultVal, updateFunc){\n let existing = this.private(el, key)\n if(existing === undefined){\n this.putPrivate(el, key, updateFunc(defaultVal))\n } else {\n this.putPrivate(el, key, updateFunc(existing))\n }\n },\n\n copyPrivates(target, source){\n if(source[PHX_PRIVATE]){\n target[PHX_PRIVATE] = source[PHX_PRIVATE]\n }\n },\n\n putTitle(str){\n let titleEl = document.querySelector(\"title\")\n let {prefix, suffix} = titleEl.dataset\n document.title = `${prefix || \"\"}${str}${suffix || \"\"}`\n },\n\n debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, callback){\n let debounce = el.getAttribute(phxDebounce)\n let throttle = el.getAttribute(phxThrottle)\n if(debounce === \"\"){ debounce = defaultDebounce }\n if(throttle === \"\"){ throttle = defaultThrottle }\n let value = debounce || throttle\n switch(value){\n case null: return callback()\n\n case \"blur\":\n if(this.once(el, \"debounce-blur\")){\n el.addEventListener(\"blur\", () => callback())\n }\n return\n\n default:\n let timeout = parseInt(value)\n let trigger = () => throttle ? this.deletePrivate(el, THROTTLED) : callback()\n let currentCycle = this.incCycle(el, DEBOUNCE_TRIGGER, trigger)\n if(isNaN(timeout)){ return logError(`invalid throttle/debounce value: ${value}`) }\n if(throttle){\n let newKeyDown = false\n if(event.type === \"keydown\"){\n let prevKey = this.private(el, DEBOUNCE_PREV_KEY)\n this.putPrivate(el, DEBOUNCE_PREV_KEY, event.key)\n newKeyDown = prevKey !== event.key\n }\n\n if(!newKeyDown && this.private(el, THROTTLED)){\n return false\n } else {\n callback()\n this.putPrivate(el, THROTTLED, true)\n setTimeout(() => {\n if(asyncFilter()){ this.triggerCycle(el, DEBOUNCE_TRIGGER) }\n }, timeout)\n }\n } else {\n setTimeout(() => {\n if(asyncFilter()){ this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle) }\n }, timeout)\n }\n\n let form = el.form\n if(form && this.once(form, \"bind-debounce\")){\n form.addEventListener(\"submit\", () => {\n Array.from((new FormData(form)).entries(), ([name]) => {\n let input = form.querySelector(`[name=\"${name}\"]`)\n this.incCycle(input, DEBOUNCE_TRIGGER)\n this.deletePrivate(input, THROTTLED)\n })\n })\n }\n if(this.once(el, \"bind-debounce\")){\n el.addEventListener(\"blur\", () => this.triggerCycle(el, DEBOUNCE_TRIGGER))\n }\n }\n },\n\n triggerCycle(el, key, currentCycle){\n let [cycle, trigger] = this.private(el, key)\n if(!currentCycle){ currentCycle = cycle }\n if(currentCycle === cycle){\n this.incCycle(el, key)\n trigger()\n }\n },\n\n once(el, key){\n if(this.private(el, key) === true){ return false }\n this.putPrivate(el, key, true)\n return true\n },\n\n incCycle(el, key, trigger = function (){ }){\n let [currentCycle] = this.private(el, key) || [0, trigger]\n currentCycle++\n this.putPrivate(el, key, [currentCycle, trigger])\n return currentCycle\n },\n\n discardError(container, el, phxFeedbackFor){\n let field = el.getAttribute && el.getAttribute(phxFeedbackFor)\n // TODO: Remove id lookup after we update Phoenix to use input_name instead of input_id\n let input = field && container.querySelector(`[id=\"${field}\"], [name=\"${field}\"]`)\n if(!input){ return }\n\n if(!(this.private(input, PHX_HAS_FOCUSED) || this.private(input.form, PHX_HAS_SUBMITTED))){\n el.classList.add(PHX_NO_FEEDBACK_CLASS)\n }\n },\n\n showError(inputEl, phxFeedbackFor){\n if(inputEl.id || inputEl.name){\n this.all(inputEl.form, `[${phxFeedbackFor}=\"${inputEl.id}\"], [${phxFeedbackFor}=\"${inputEl.name}\"]`, (el) => {\n this.removeClass(el, PHX_NO_FEEDBACK_CLASS)\n })\n }\n },\n\n isPhxChild(node){\n return node.getAttribute && node.getAttribute(PHX_PARENT_ID)\n },\n\n isPhxSticky(node){\n return node.getAttribute && node.getAttribute(PHX_STICKY) !== null\n },\n\n firstPhxChild(el){\n return this.isPhxChild(el) ? el : this.all(el, `[${PHX_PARENT_ID}]`)[0]\n },\n\n dispatchEvent(target, name, opts = {}){\n let bubbles = opts.bubbles === undefined ? true : !!opts.bubbles\n let eventOpts = {bubbles: bubbles, cancelable: true, detail: opts.detail || {}}\n let event = name === \"click\" ? new MouseEvent(\"click\", eventOpts) : new CustomEvent(name, eventOpts)\n target.dispatchEvent(event)\n },\n\n cloneNode(node, html){\n if(typeof (html) === \"undefined\"){\n return node.cloneNode(true)\n } else {\n let cloned = node.cloneNode(false)\n cloned.innerHTML = html\n return cloned\n }\n },\n\n mergeAttrs(target, source, opts = {}){\n let exclude = opts.exclude || []\n let isIgnored = opts.isIgnored\n let sourceAttrs = source.attributes\n for(let i = sourceAttrs.length - 1; i >= 0; i--){\n let name = sourceAttrs[i].name\n if(exclude.indexOf(name) < 0){ target.setAttribute(name, source.getAttribute(name)) }\n }\n\n let targetAttrs = target.attributes\n for(let i = targetAttrs.length - 1; i >= 0; i--){\n let name = targetAttrs[i].name\n if(isIgnored){\n if(name.startsWith(\"data-\") && !source.hasAttribute(name)){ target.removeAttribute(name) }\n } else {\n if(!source.hasAttribute(name)){ target.removeAttribute(name) }\n }\n }\n },\n\n mergeFocusedInput(target, source){\n // skip selects because FF will reset highlighted index for any setAttribute\n if(!(target instanceof HTMLSelectElement)){ DOM.mergeAttrs(target, source, {exclude: [\"value\"]}) }\n if(source.readOnly){\n target.setAttribute(\"readonly\", true)\n } else {\n target.removeAttribute(\"readonly\")\n }\n },\n\n hasSelectionRange(el){\n return el.setSelectionRange && (el.type === \"text\" || el.type === \"textarea\")\n },\n\n restoreFocus(focused, selectionStart, selectionEnd){\n if(!DOM.isTextualInput(focused)){ return }\n let wasFocused = focused.matches(\":focus\")\n if(focused.readOnly){ focused.blur() }\n if(!wasFocused){ focused.focus() }\n if(this.hasSelectionRange(focused)){\n focused.setSelectionRange(selectionStart, selectionEnd)\n }\n },\n\n isFormInput(el){ return /^(?:input|select|textarea)$/i.test(el.tagName) && el.type !== \"button\" },\n\n syncAttrsToProps(el){\n if(el instanceof HTMLInputElement && CHECKABLE_INPUTS.indexOf(el.type.toLocaleLowerCase()) >= 0){\n el.checked = el.getAttribute(\"checked\") !== null\n }\n },\n\n isTextualInput(el){ return FOCUSABLE_INPUTS.indexOf(el.type) >= 0 },\n\n isNowTriggerFormExternal(el, phxTriggerExternal){\n return el.getAttribute && el.getAttribute(phxTriggerExternal) !== null\n },\n\n syncPendingRef(fromEl, toEl, disableWith){\n let ref = fromEl.getAttribute(PHX_REF)\n if(ref === null){ return true }\n let refSrc = fromEl.getAttribute(PHX_REF_SRC)\n\n if(DOM.isFormInput(fromEl) || fromEl.getAttribute(disableWith) !== null){\n if(DOM.isUploadInput(fromEl)){ DOM.mergeAttrs(fromEl, toEl, {isIgnored: true}) }\n DOM.putPrivate(fromEl, PHX_REF, toEl)\n return false\n } else {\n PHX_EVENT_CLASSES.forEach(className => {\n fromEl.classList.contains(className) && toEl.classList.add(className)\n })\n toEl.setAttribute(PHX_REF, ref)\n toEl.setAttribute(PHX_REF_SRC, refSrc)\n return true\n }\n },\n\n cleanChildNodes(container, phxUpdate){\n if(DOM.isPhxUpdate(container, phxUpdate, [\"append\", \"prepend\"])){\n let toRemove = []\n container.childNodes.forEach(childNode => {\n if(!childNode.id){\n // Skip warning if it's an empty text node (e.g. a new-line)\n let isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim() === \"\"\n if(!isEmptyTextNode){\n logError(\"only HTML element tags with an id are allowed inside containers with phx-update.\\n\\n\" +\n `removing illegal node: \"${(childNode.outerHTML || childNode.nodeValue).trim()}\"\\n\\n`)\n }\n toRemove.push(childNode)\n }\n })\n toRemove.forEach(childNode => childNode.remove())\n }\n },\n\n replaceRootContainer(container, tagName, attrs){\n let retainedAttrs = new Set([\"id\", PHX_SESSION, PHX_STATIC, PHX_MAIN, PHX_ROOT_ID])\n if(container.tagName.toLowerCase() === tagName.toLowerCase()){\n Array.from(container.attributes)\n .filter(attr => !retainedAttrs.has(attr.name.toLowerCase()))\n .forEach(attr => container.removeAttribute(attr.name))\n\n Object.keys(attrs)\n .filter(name => !retainedAttrs.has(name.toLowerCase()))\n .forEach(attr => container.setAttribute(attr, attrs[attr]))\n\n return container\n\n } else {\n let newContainer = document.createElement(tagName)\n Object.keys(attrs).forEach(attr => newContainer.setAttribute(attr, attrs[attr]))\n retainedAttrs.forEach(attr => newContainer.setAttribute(attr, container.getAttribute(attr)))\n newContainer.innerHTML = container.innerHTML\n container.replaceWith(newContainer)\n return newContainer\n }\n },\n\n getSticky(el, name, defaultVal){\n let op = (DOM.private(el, \"sticky\") || []).find(([existingName, ]) => name === existingName)\n if(op){\n let [_name, _op, stashedResult] = op\n return stashedResult\n } else {\n return typeof(defaultVal) === \"function\" ? defaultVal() : defaultVal\n }\n },\n\n deleteSticky(el, name){\n this.updatePrivate(el, \"sticky\", [], ops => {\n return ops.filter(([existingName, _]) => existingName !== name)\n })\n },\n\n putSticky(el, name, op){\n let stashedResult = op(el)\n this.updatePrivate(el, \"sticky\", [], ops => {\n let existingIndex = ops.findIndex(([existingName, ]) => name === existingName)\n if(existingIndex >= 0){\n ops[existingIndex] = [name, op, stashedResult]\n } else {\n ops.push([name, op, stashedResult])\n }\n return ops\n })\n },\n\n applyStickyOperations(el){\n let ops = DOM.private(el, \"sticky\")\n if(!ops){ return }\n\n ops.forEach(([name, op, _stashed]) => this.putSticky(el, name, op))\n }\n}\n\nexport default DOM\n", "import {\n PHX_ACTIVE_ENTRY_REFS,\n PHX_LIVE_FILE_UPDATED,\n PHX_PREFLIGHTED_REFS\n} from \"./constants\"\n\nimport {\n channelUploader,\n logError\n} from \"./utils\"\n\nimport LiveUploader from \"./live_uploader\"\n\nexport default class UploadEntry {\n static isActive(fileEl, file){\n let isNew = file._phxRef === undefined\n let activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(\",\")\n let isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0\n return file.size > 0 && (isNew || isActive)\n }\n\n static isPreflighted(fileEl, file){\n let preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(\",\")\n let isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0\n return isPreflighted && this.isActive(fileEl, file)\n }\n\n constructor(fileEl, file, view){\n this.ref = LiveUploader.genFileRef(file)\n this.fileEl = fileEl\n this.file = file\n this.view = view\n this.meta = null\n this._isCancelled = false\n this._isDone = false\n this._progress = 0\n this._lastProgressSent = -1\n this._onDone = function (){ }\n this._onElUpdated = this.onElUpdated.bind(this)\n this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated)\n }\n\n metadata(){ return this.meta }\n\n progress(progress){\n this._progress = Math.floor(progress)\n if(this._progress > this._lastProgressSent){\n if(this._progress >= 100){\n this._progress = 100\n this._lastProgressSent = 100\n this._isDone = true\n this.view.pushFileProgress(this.fileEl, this.ref, 100, () => {\n LiveUploader.untrackFile(this.fileEl, this.file)\n this._onDone()\n })\n } else {\n this._lastProgressSent = this._progress\n this.view.pushFileProgress(this.fileEl, this.ref, this._progress)\n }\n }\n }\n\n cancel(){\n this._isCancelled = true\n this._isDone = true\n this._onDone()\n }\n\n isDone(){ return this._isDone }\n\n error(reason = \"failed\"){\n this.view.pushFileProgress(this.fileEl, this.ref, {error: reason})\n LiveUploader.clearFiles(this.fileEl)\n }\n\n //private\n\n onDone(callback){\n this._onDone = () => {\n this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated)\n callback()\n }\n }\n\n onElUpdated(){\n let activeRefs = this.fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(\",\")\n if(activeRefs.indexOf(this.ref) === -1){ this.cancel() }\n }\n\n toPreflightPayload(){\n return {\n last_modified: this.file.lastModified,\n name: this.file.name,\n size: this.file.size,\n type: this.file.type,\n ref: this.ref\n }\n }\n\n uploader(uploaders){\n if(this.meta.uploader){\n let callback = uploaders[this.meta.uploader] || logError(`no uploader configured for ${this.meta.uploader}`)\n return {name: this.meta.uploader, callback: callback}\n } else {\n return {name: \"channel\", callback: channelUploader}\n }\n }\n\n zipPostFlight(resp){\n this.meta = resp.entries[this.ref]\n if(!this.meta){ logError(`no preflight upload response returned with ref ${this.ref}`, {input: this.fileEl, response: resp}) }\n }\n}\n", "import {\n PHX_DONE_REFS,\n PHX_PREFLIGHTED_REFS,\n PHX_UPLOAD_REF\n} from \"./constants\"\n\nimport {\n} from \"./utils\"\n\nimport DOM from \"./dom\"\nimport UploadEntry from \"./upload_entry\"\n\nlet liveUploaderFileRef = 0\n\nexport default class LiveUploader {\n static genFileRef(file){\n let ref = file._phxRef\n if(ref !== undefined){\n return ref\n } else {\n file._phxRef = (liveUploaderFileRef++).toString()\n return file._phxRef\n }\n }\n\n static getEntryDataURL(inputEl, ref, callback){\n let file = this.activeFiles(inputEl).find(file => this.genFileRef(file) === ref)\n callback(URL.createObjectURL(file))\n }\n\n static hasUploadsInProgress(formEl){\n let active = 0\n DOM.findUploadInputs(formEl).forEach(input => {\n if(input.getAttribute(PHX_PREFLIGHTED_REFS) !== input.getAttribute(PHX_DONE_REFS)){\n active++\n }\n })\n return active > 0\n }\n\n static serializeUploads(inputEl){\n let files = this.activeFiles(inputEl)\n let fileData = {}\n files.forEach(file => {\n let entry = {path: inputEl.name}\n let uploadRef = inputEl.getAttribute(PHX_UPLOAD_REF)\n fileData[uploadRef] = fileData[uploadRef] || []\n entry.ref = this.genFileRef(file)\n entry.name = file.name || entry.ref\n entry.type = file.type\n entry.size = file.size\n fileData[uploadRef].push(entry)\n })\n return fileData\n }\n\n static clearFiles(inputEl){\n inputEl.value = null\n inputEl.removeAttribute(PHX_UPLOAD_REF)\n DOM.putPrivate(inputEl, \"files\", [])\n }\n\n static untrackFile(inputEl, file){\n DOM.putPrivate(inputEl, \"files\", DOM.private(inputEl, \"files\").filter(f => !Object.is(f, file)))\n }\n\n static trackFiles(inputEl, files){\n if(inputEl.getAttribute(\"multiple\") !== null){\n let newFiles = files.filter(file => !this.activeFiles(inputEl).find(f => Object.is(f, file)))\n DOM.putPrivate(inputEl, \"files\", this.activeFiles(inputEl).concat(newFiles))\n inputEl.value = null\n } else {\n DOM.putPrivate(inputEl, \"files\", files)\n }\n }\n\n static activeFileInputs(formEl){\n let fileInputs = DOM.findUploadInputs(formEl)\n return Array.from(fileInputs).filter(el => el.files && this.activeFiles(el).length > 0)\n }\n\n static activeFiles(input){\n return (DOM.private(input, \"files\") || []).filter(f => UploadEntry.isActive(input, f))\n }\n\n static inputsAwaitingPreflight(formEl){\n let fileInputs = DOM.findUploadInputs(formEl)\n return Array.from(fileInputs).filter(input => this.filesAwaitingPreflight(input).length > 0)\n }\n\n static filesAwaitingPreflight(input){\n return this.activeFiles(input).filter(f => !UploadEntry.isPreflighted(input, f))\n }\n\n constructor(inputEl, view, onComplete){\n this.view = view\n this.onComplete = onComplete\n this._entries =\n Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || [])\n .map(file => new UploadEntry(inputEl, file, view))\n\n this.numEntriesInProgress = this._entries.length\n }\n\n entries(){ return this._entries }\n\n initAdapterUpload(resp, onError, liveSocket){\n this._entries =\n this._entries.map(entry => {\n entry.zipPostFlight(resp)\n entry.onDone(() => {\n this.numEntriesInProgress--\n if(this.numEntriesInProgress === 0){ this.onComplete() }\n })\n return entry\n })\n\n let groupedEntries = this._entries.reduce((acc, entry) => {\n let {name, callback} = entry.uploader(liveSocket.uploaders)\n acc[name] = acc[name] || {callback: callback, entries: []}\n acc[name].entries.push(entry)\n return acc\n }, {})\n\n for(let name in groupedEntries){\n let {callback, entries} = groupedEntries[name]\n callback(entries, onError, resp, liveSocket)\n }\n }\n}\n", "import {\n PHX_ACTIVE_ENTRY_REFS,\n PHX_LIVE_FILE_UPDATED,\n PHX_PREFLIGHTED_REFS,\n PHX_UPLOAD_REF\n} from \"./constants\"\n\nimport LiveUploader from \"./live_uploader\"\n\nlet Hooks = {\n LiveFileUpload: {\n activeRefs(){ return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS) },\n\n preflightedRefs(){ return this.el.getAttribute(PHX_PREFLIGHTED_REFS) },\n\n mounted(){ this.preflightedWas = this.preflightedRefs() },\n\n updated(){\n let newPreflights = this.preflightedRefs()\n if(this.preflightedWas !== newPreflights){\n this.preflightedWas = newPreflights\n if(newPreflights === \"\"){\n this.__view.cancelSubmit(this.el.form)\n }\n }\n\n if(this.activeRefs() === \"\"){ this.el.value = null }\n this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED))\n }\n },\n\n LiveImgPreview: {\n mounted(){\n this.ref = this.el.getAttribute(\"data-phx-entry-ref\")\n this.inputEl = document.getElementById(this.el.getAttribute(PHX_UPLOAD_REF))\n LiveUploader.getEntryDataURL(this.inputEl, this.ref, url => {\n this.url = url\n this.el.src = url\n })\n },\n destroyed(){\n URL.revokeObjectURL(this.url)\n }\n }\n}\n\nexport default Hooks\n", "import {\n maybe\n} from \"./utils\"\n\nimport DOM from \"./dom\"\n\nexport default class DOMPostMorphRestorer {\n constructor(containerBefore, containerAfter, updateType){\n let idsBefore = new Set()\n let idsAfter = new Set([...containerAfter.children].map(child => child.id))\n\n let elementsToModify = []\n\n Array.from(containerBefore.children).forEach(child => {\n if(child.id){ // all of our children should be elements with ids\n idsBefore.add(child.id)\n if(idsAfter.has(child.id)){\n let previousElementId = child.previousElementSibling && child.previousElementSibling.id\n elementsToModify.push({elementId: child.id, previousElementId: previousElementId})\n }\n }\n })\n\n this.containerId = containerAfter.id\n this.updateType = updateType\n this.elementsToModify = elementsToModify\n this.elementIdsToAdd = [...idsAfter].filter(id => !idsBefore.has(id))\n }\n\n // We do the following to optimize append/prepend operations:\n // 1) Track ids of modified elements & of new elements\n // 2) All the modified elements are put back in the correct position in the DOM tree\n // by storing the id of their previous sibling\n // 3) New elements are going to be put in the right place by morphdom during append.\n // For prepend, we move them to the first position in the container\n perform(){\n let container = DOM.byId(this.containerId)\n this.elementsToModify.forEach(elementToModify => {\n if(elementToModify.previousElementId){\n maybe(document.getElementById(elementToModify.previousElementId), previousElem => {\n maybe(document.getElementById(elementToModify.elementId), elem => {\n let isInRightPlace = elem.previousElementSibling && elem.previousElementSibling.id == previousElem.id\n if(!isInRightPlace){\n previousElem.insertAdjacentElement(\"afterend\", elem)\n }\n })\n })\n } else {\n // This is the first element in the container\n maybe(document.getElementById(elementToModify.elementId), elem => {\n let isInRightPlace = elem.previousElementSibling == null\n if(!isInRightPlace){\n container.insertAdjacentElement(\"afterbegin\", elem)\n }\n })\n }\n })\n\n if(this.updateType == \"prepend\"){\n this.elementIdsToAdd.reverse().forEach(elemId => {\n maybe(document.getElementById(elemId), elem => container.insertAdjacentElement(\"afterbegin\", elem))\n })\n }\n }\n}\n", "var DOCUMENT_FRAGMENT_NODE = 11;\n\nfunction morphAttrs(fromNode, toNode) {\n var toNodeAttrs = toNode.attributes;\n var attr;\n var attrName;\n var attrNamespaceURI;\n var attrValue;\n var fromValue;\n\n // document-fragments dont have attributes so lets not do anything\n if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {\n return;\n }\n\n // update attributes on original DOM element\n for (var i = toNodeAttrs.length - 1; i >= 0; i--) {\n attr = toNodeAttrs[i];\n attrName = attr.name;\n attrNamespaceURI = attr.namespaceURI;\n attrValue = attr.value;\n\n if (attrNamespaceURI) {\n attrName = attr.localName || attrName;\n fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);\n\n if (fromValue !== attrValue) {\n if (attr.prefix === 'xmlns'){\n attrName = attr.name; // It's not allowed to set an attribute with the XMLNS namespace without specifying the `xmlns` prefix\n }\n fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);\n }\n } else {\n fromValue = fromNode.getAttribute(attrName);\n\n if (fromValue !== attrValue) {\n fromNode.setAttribute(attrName, attrValue);\n }\n }\n }\n\n // Remove any extra attributes found on the original DOM element that\n // weren't found on the target element.\n var fromNodeAttrs = fromNode.attributes;\n\n for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {\n attr = fromNodeAttrs[d];\n attrName = attr.name;\n attrNamespaceURI = attr.namespaceURI;\n\n if (attrNamespaceURI) {\n attrName = attr.localName || attrName;\n\n if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {\n fromNode.removeAttributeNS(attrNamespaceURI, attrName);\n }\n } else {\n if (!toNode.hasAttribute(attrName)) {\n fromNode.removeAttribute(attrName);\n }\n }\n }\n}\n\nvar range; // Create a range object for efficently rendering strings to elements.\nvar NS_XHTML = 'http://www.w3.org/1999/xhtml';\n\nvar doc = typeof document === 'undefined' ? undefined : document;\nvar HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template');\nvar HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange();\n\nfunction createFragmentFromTemplate(str) {\n var template = doc.createElement('template');\n template.innerHTML = str;\n return template.content.childNodes[0];\n}\n\nfunction createFragmentFromRange(str) {\n if (!range) {\n range = doc.createRange();\n range.selectNode(doc.body);\n }\n\n var fragment = range.createContextualFragment(str);\n return fragment.childNodes[0];\n}\n\nfunction createFragmentFromWrap(str) {\n var fragment = doc.createElement('body');\n fragment.innerHTML = str;\n return fragment.childNodes[0];\n}\n\n/**\n * This is about the same\n * var html = new DOMParser().parseFromString(str, 'text/html');\n * return html.body.firstChild;\n *\n * @method toElement\n * @param {String} str\n */\nfunction toElement(str) {\n str = str.trim();\n if (HAS_TEMPLATE_SUPPORT) {\n // avoid restrictions on content for things like `<tr><th>Hi</th></tr>` which\n // createContextualFragment doesn't support\n // <template> support not available in IE\n return createFragmentFromTemplate(str);\n } else if (HAS_RANGE_SUPPORT) {\n return createFragmentFromRange(str);\n }\n\n return createFragmentFromWrap(str);\n}\n\n/**\n * Returns true if two node's names are the same.\n *\n * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same\n * nodeName and different namespace URIs.\n *\n * @param {Element} a\n * @param {Element} b The target element\n * @return {boolean}\n */\nfunction compareNodeNames(fromEl, toEl) {\n var fromNodeName = fromEl.nodeName;\n var toNodeName = toEl.nodeName;\n var fromCodeStart, toCodeStart;\n\n if (fromNodeName === toNodeName) {\n return true;\n }\n\n fromCodeStart = fromNodeName.charCodeAt(0);\n toCodeStart = toNodeName.charCodeAt(0);\n\n // If the target element is a virtual DOM node or SVG node then we may\n // need to normalize the tag name before comparing. Normal HTML elements that are\n // in the \"http://www.w3.org/1999/xhtml\"\n // are converted to upper case\n if (fromCodeStart <= 90 && toCodeStart >= 97) { // from is upper and to is lower\n return fromNodeName === toNodeName.toUpperCase();\n } else if (toCodeStart <= 90 && fromCodeStart >= 97) { // to is upper and from is lower\n return toNodeName === fromNodeName.toUpperCase();\n } else {\n return false;\n }\n}\n\n/**\n * Create an element, optionally with a known namespace URI.\n *\n * @param {string} name the element name, e.g. 'div' or 'svg'\n * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of\n * its `xmlns` attribute or its inferred namespace.\n *\n * @return {Element}\n */\nfunction createElementNS(name, namespaceURI) {\n return !namespaceURI || namespaceURI === NS_XHTML ?\n doc.createElement(name) :\n doc.createElementNS(namespaceURI, name);\n}\n\n/**\n * Copies the children of one DOM element to another DOM element\n */\nfunction moveChildren(fromEl, toEl) {\n var curChild = fromEl.firstChild;\n while (curChild) {\n var nextChild = curChild.nextSibling;\n toEl.appendChild(curChild);\n curChild = nextChild;\n }\n return toEl;\n}\n\nfunction syncBooleanAttrProp(fromEl, toEl, name) {\n if (fromEl[name] !== toEl[name]) {\n fromEl[name] = toEl[name];\n if (fromEl[name]) {\n fromEl.setAttribute(name, '');\n } else {\n fromEl.removeAttribute(name);\n }\n }\n}\n\nvar specialElHandlers = {\n OPTION: function(fromEl, toEl) {\n var parentNode = fromEl.parentNode;\n if (parentNode) {\n var parentName = parentNode.nodeName.toUpperCase();\n if (parentName === 'OPTGROUP') {\n parentNode = parentNode.parentNode;\n parentName = parentNode && parentNode.nodeName.toUpperCase();\n }\n if (parentName === 'SELECT' && !parentNode.hasAttribute('multiple')) {\n if (fromEl.hasAttribute('selected') && !toEl.selected) {\n // Workaround for MS Edge bug where the 'selected' attribute can only be\n // removed if set to a non-empty value:\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12087679/\n fromEl.setAttribute('selected', 'selected');\n fromEl.removeAttribute('selected');\n }\n // We have to reset select element's selectedIndex to -1, otherwise setting\n // fromEl.selected using the syncBooleanAttrProp below has no effect.\n // The correct selectedIndex will be set in the SELECT special handler below.\n parentNode.selectedIndex = -1;\n }\n }\n syncBooleanAttrProp(fromEl, toEl, 'selected');\n },\n /**\n * The \"value\" attribute is special for the <input> element since it sets\n * the initial value. Changing the \"value\" attribute without changing the\n * \"value\" property will have no effect since it is only used to the set the\n * initial value. Similar for the \"checked\" attribute, and \"disabled\".\n */\n INPUT: function(fromEl, toEl) {\n syncBooleanAttrProp(fromEl, toEl, 'checked');\n syncBooleanAttrProp(fromEl, toEl, 'disabled');\n\n if (fromEl.value !== toEl.value) {\n fromEl.value = toEl.value;\n }\n\n if (!toEl.hasAttribute('value')) {\n fromEl.removeAttribute('value');\n }\n },\n\n TEXTAREA: function(fromEl, toEl) {\n var newValue = toEl.value;\n if (fromEl.value !== newValue) {\n fromEl.value = newValue;\n }\n\n var firstChild = fromEl.firstChild;\n if (firstChild) {\n // Needed for IE. Apparently IE sets the placeholder as the\n // node value and vise versa. This ignores an empty update.\n var oldValue = firstChild.nodeValue;\n\n if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {\n return;\n }\n\n firstChild.nodeValue = newValue;\n }\n },\n SELECT: function(fromEl, toEl) {\n if (!toEl.hasAttribute('multiple')) {\n var selectedIndex = -1;\n var i = 0;\n // We have to loop through children of fromEl, not toEl since nodes can be moved\n // from toEl to fromEl directly when morphing.\n // At the time this special handler is invoked, all children have already been morphed\n // and appended to / removed from fromEl, so using fromEl here is safe and correct.\n var curChild = fromEl.firstChild;\n var optgroup;\n var nodeName;\n while(curChild) {\n nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();\n if (nodeName === 'OPTGROUP') {\n optgroup = curChild;\n curChild = optgroup.firstChild;\n } else {\n if (nodeName === 'OPTION') {\n if (curChild.hasAttribute('selected')) {\n selectedIndex = i;\n break;\n }\n i++;\n }\n curChild = curChild.nextSibling;\n if (!curChild && optgroup) {\n curChild = optgroup.nextSibling;\n optgroup = null;\n }\n }\n }\n\n fromEl.selectedIndex = selectedIndex;\n }\n }\n};\n\nvar ELEMENT_NODE = 1;\nvar DOCUMENT_FRAGMENT_NODE$1 = 11;\nvar TEXT_NODE = 3;\nvar COMMENT_NODE = 8;\n\nfunction noop() {}\n\nfunction defaultGetNodeKey(node) {\n if (node) {\n return (node.getAttribute && node.getAttribute('id')) || node.id;\n }\n}\n\nfunction morphdomFactory(morphAttrs) {\n\n return function morphdom(fromNode, toNode, options) {\n if (!options) {\n options = {};\n }\n\n if (typeof toNode === 'string') {\n if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') {\n var toNodeHtml = toNode;\n toNode = doc.createElement('html');\n toNode.innerHTML = toNodeHtml;\n } else {\n toNode = toElement(toNode);\n }\n }\n\n var getNodeKey = options.getNodeKey || defaultGetNodeKey;\n var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;\n var onNodeAdded = options.onNodeAdded || noop;\n var onBeforeElUpdated = options.onBeforeElUpdated || noop;\n var onElUpdated = options.onElUpdated || noop;\n var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;\n var onNodeDiscarded = options.onNodeDiscarded || noop;\n var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;\n var childrenOnly = options.childrenOnly === true;\n\n // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.\n var fromNodesLookup = Object.create(null);\n var keyedRemovalList = [];\n\n function addKeyedRemoval(key) {\n keyedRemovalList.push(key);\n }\n\n function walkDiscardedChildNodes(node, skipKeyedNodes) {\n if (node.nodeType === ELEMENT_NODE) {\n var curChild = node.firstChild;\n while (curChild) {\n\n var key = undefined;\n\n if (skipKeyedNodes && (key = getNodeKey(curChild))) {\n // If we are skipping keyed nodes then we add the key\n // to a list so that it can be handled at the very end.\n addKeyedRemoval(key);\n } else {\n // Only report the node as discarded if it is not keyed. We do this because\n // at the end we loop through all keyed elements that were unmatched\n // and then discard them in one final pass.\n onNodeDiscarded(curChild);\n if (curChild.firstChild) {\n walkDiscardedChildNodes(curChild, skipKeyedNodes);\n }\n }\n\n curChild = curChild.nextSibling;\n }\n }\n }\n\n /**\n * Removes a DOM node out of the original DOM\n *\n * @param {Node} node The node to remove\n * @param {Node} parentNode The nodes parent\n * @param {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.\n * @return {undefined}\n */\n function removeNode(node, parentNode, skipKeyedNodes) {\n if (onBeforeNodeDiscarded(node) === false) {\n return;\n }\n\n if (parentNode) {\n parentNode.removeChild(node);\n }\n\n onNodeDiscarded(node);\n walkDiscardedChildNodes(node, skipKeyedNodes);\n }\n\n // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future\n // function indexTree(root) {\n // var treeWalker = document.createTreeWalker(\n // root,\n // NodeFilter.SHOW_ELEMENT);\n //\n // var el;\n // while((el = treeWalker.nextNode())) {\n // var key = getNodeKey(el);\n // if (key) {\n // fromNodesLookup[key] = el;\n // }\n // }\n // }\n\n // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future\n //\n // function indexTree(node) {\n // var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);\n // var el;\n // while((el = nodeIterator.nextNode())) {\n // var key = getNodeKey(el);\n // if (key) {\n // fromNodesLookup[key] = el;\n // }\n // }\n // }\n\n function indexTree(node) {\n if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {\n var curChild = node.firstChild;\n while (curChild) {\n var key = getNodeKey(curChild);\n if (key) {\n fromNodesLookup[key] = curChild;\n }\n\n // Walk recursively\n indexTree(curChild);\n\n curChild = curChild.nextSibling;\n }\n }\n }\n\n indexTree(fromNode);\n\n function handleNodeAdded(el) {\n onNodeAdded(el);\n\n var curChild = el.firstChild;\n while (curChild) {\n var nextSibling = curChild.nextSibling;\n\n var key = getNodeKey(curChild);\n if (key) {\n var unmatchedFromEl = fromNodesLookup[key];\n // if we find a duplicate #id node in cache, replace `el` with cache value\n // and morph it to the child node.\n if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {\n curChild.parentNode.replaceChild(unmatchedFromEl, curChild);\n morphEl(unmatchedFromEl, curChild);\n } else {\n handleNodeAdded(curChild);\n }\n } else {\n // recursively call for curChild and it's children to see if we find something in\n // fromNodesLookup\n handleNodeAdded(curChild);\n }\n\n curChild = nextSibling;\n }\n }\n\n function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {\n // We have processed all of the \"to nodes\". If curFromNodeChild is\n // non-null then we still have some from nodes left over that need\n // to be removed\n while (curFromNodeChild) {\n var fromNextSibling = curFromNodeChild.nextSibling;\n if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {\n // Since the node is keyed it might be matched up later so we defer\n // the actual removal to later\n addKeyedRemoval(curFromNodeKey);\n } else {\n // NOTE: we skip nested keyed nodes from being removed since there is\n // still a chance they will be matched up later\n removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);\n }\n curFromNodeChild = fromNextSibling;\n }\n }\n\n function morphEl(fromEl, toEl, childrenOnly) {\n var toElKey = getNodeKey(toEl);\n\n if (toElKey) {\n // If an element with an ID is being morphed then it will be in the final\n // DOM so clear it out of the saved elements collection\n delete fromNodesLookup[toElKey];\n }\n\n if (!childrenOnly) {\n // optional\n if (onBeforeElUpdated(fromEl, toEl) === false) {\n return;\n }\n\n // update attributes on original DOM element first\n morphAttrs(fromEl, toEl);\n // optional\n onElUpdated(fromEl);\n\n if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {\n return;\n }\n }\n\n if (fromEl.nodeName !== 'TEXTAREA') {\n morphChildren(fromEl, toEl);\n } else {\n specialElHandlers.TEXTAREA(fromEl, toEl);\n }\n }\n\n function morphChildren(fromEl, toEl) {\n var curToNodeChild = toEl.firstChild;\n var curFromNodeChild = fromEl.firstChild;\n var curToNodeKey;\n var curFromNodeKey;\n\n var fromNextSibling;\n var toNextSibling;\n var matchingFromEl;\n\n // walk the children\n outer: while (curToNodeChild) {\n toNextSibling = curToNodeChild.nextSibling;\n curToNodeKey = getNodeKey(curToNodeChild);\n\n // walk the fromNode children all the way through\n while (curFromNodeChild) {\n fromNextSibling = curFromNodeChild.nextSibling;\n\n if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {\n curToNodeChild = toNextSibling;\n curFromNodeChild = fromNextSibling;\n continue outer;\n }\n\n curFromNodeKey = getNodeKey(curFromNodeChild);\n\n var curFromNodeType = curFromNodeChild.nodeType;\n\n // this means if the curFromNodeChild doesnt have a match with the curToNodeChild\n var isCompatible = undefined;\n\n if (curFromNodeType === curToNodeChild.nodeType) {\n if (curFromNodeType === ELEMENT_NODE) {\n // Both nodes being compared are Element nodes\n\n if (curToNodeKey) {\n // The target node has a key so we want to match it up with the correct element\n // in the original DOM tree\n if (curToNodeKey !== curFromNodeKey) {\n // The current element in the original DOM tree does not have a matching key so\n // let's check our lookup to see if there is a matching element in the original\n // DOM tree\n if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {\n if (fromNextSibling === matchingFromEl) {\n // Special case for single element removals. To avoid removing the original\n // DOM node out of the tree (since that can break CSS transitions, etc.),\n // we will instead discard the current node and wait until the next\n // iteration to properly match up the keyed target element with its matching\n // element in the original tree\n isCompatible = false;\n } else {\n // We found a matching keyed element somewhere in the original DOM tree.\n // Let's move the original DOM node into the current position and morph\n // it.\n\n // NOTE: We use insertBefore instead of replaceChild because we want to go through\n // the `removeNode()` function for the node that is being discarded so that\n // all lifecycle hooks are correctly invoked\n fromEl.insertBefore(matchingFromEl, curFromNodeChild);\n\n // fromNextSibling = curFromNodeChild.nextSibling;\n\n if (curFromNodeKey) {\n // Since the node is keyed it might be matched up later so we defer\n // the actual removal to later\n addKeyedRemoval(curFromNodeKey);\n } else {\n // NOTE: we skip nested keyed nodes from being removed since there is\n // still a chance they will be matched up later\n removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);\n }\n\n curFromNodeChild = matchingFromEl;\n }\n } else {\n // The nodes are not compatible since the \"to\" node has a key and there\n // is no matching keyed node in the source tree\n isCompatible = false;\n }\n }\n } else if (curFromNodeKey) {\n // The original has a key\n isCompatible = false;\n }\n\n isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);\n if (isCompatible) {\n // We found compatible DOM elements so transform\n // the current \"from\" node to match the current\n // target DOM node.\n // MORPH\n morphEl(curFromNodeChild, curToNodeChild);\n }\n\n } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {\n // Both nodes being compared are Text or Comment nodes\n isCompatible = true;\n // Simply update nodeValue on the original node to\n // change the text value\n if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {\n curFromNodeChild.nodeValue = curToNodeChild.nodeValue;\n }\n\n }\n }\n\n if (isCompatible) {\n // Advance both the \"to\" child and the \"from\" child since we found a match\n // Nothing else to do as we already recursively called morphChildren above\n curToNodeChild = toNextSibling;\n curFromNodeChild = fromNextSibling;\n continue outer;\n }\n\n // No compatible match so remove the old node from the DOM and continue trying to find a\n // match in the original DOM. However, we only do this if the from node is not keyed\n // since it is possible that a keyed node might match up with a node somewhere else in the\n // target tree and we don't want to discard it just yet since it still might find a\n // home in the final DOM tree. After everything is done we will remove any keyed nodes\n // that didn't find a home\n if (curFromNodeKey) {\n // Since the node is keyed it might be matched up later so we defer\n // the actual removal to later\n addKeyedRemoval(curFromNodeKey);\n } else {\n // NOTE: we skip nested keyed nodes from being removed since there is\n // still a chance they will be matched up later\n removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);\n }\n\n curFromNodeChild = fromNextSibling;\n } // END: while(curFromNodeChild) {}\n\n // If we got this far then we did not find a candidate match for\n // our \"to node\" and we exhausted all of the children \"from\"\n // nodes. Therefore, we will just append the current \"to\" node\n // to the end\n if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {\n fromEl.appendChild(matchingFromEl);\n // MORPH\n morphEl(matchingFromEl, curToNodeChild);\n } else {\n var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);\n if (onBeforeNodeAddedResult !== false) {\n if (onBeforeNodeAddedResult) {\n curToNodeChild = onBeforeNodeAddedResult;\n }\n\n if (curToNodeChild.actualize) {\n curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);\n }\n fromEl.appendChild(curToNodeChild);\n handleNodeAdded(curToNodeChild);\n }\n }\n\n curToNodeChild = toNextSibling;\n curFromNodeChild = fromNextSibling;\n }\n\n cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);\n\n var specialElHandler = specialElHandlers[fromEl.nodeName];\n if (specialElHandler) {\n specialElHandler(fromEl, toEl);\n }\n } // END: morphChildren(...)\n\n var morphedNode = fromNode;\n var morphedNodeType = morphedNode.nodeType;\n var toNodeType = toNode.nodeType;\n\n if (!childrenOnly) {\n // Handle the case where we are given two DOM nodes that are not\n // compatible (e.g. <div> --> <span> or <div> --> TEXT)\n if (morphedNodeType === ELEMENT_NODE) {\n if (toNodeType === ELEMENT_NODE) {\n if (!compareNodeNames(fromNode, toNode)) {\n onNodeDiscarded(fromNode);\n morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));\n }\n } else {\n // Going from an element node to a text node\n morphedNode = toNode;\n }\n } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node\n if (toNodeType === morphedNodeType) {\n if (morphedNode.nodeValue !== toNode.nodeValue) {\n morphedNode.nodeValue = toNode.nodeValue;\n }\n\n return morphedNode;\n } else {\n // Text node to something else\n morphedNode = toNode;\n }\n }\n }\n\n if (morphedNode === toNode) {\n // The \"to node\" was not compatible with the \"from node\" so we had to\n // toss out the \"from node\" and use the \"to node\"\n onNodeDiscarded(fromNode);\n } else {\n if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {\n return;\n }\n\n morphEl(morphedNode, toNode, childrenOnly);\n\n // We now need to loop over any keyed nodes that might need to be\n // removed. We only do the removal if we know that the keyed node\n // never found a match. When a keyed node is matched up we remove\n // it out of fromNodesLookup and we use fromNodesLookup to determine\n // if a keyed node has been matched up or not\n if (keyedRemovalList) {\n for (var i=0, len=keyedRemovalList.length; i<len; i++) {\n var elToRemove = fromNodesLookup[keyedRemovalList[i]];\n if (elToRemove) {\n removeNode(elToRemove, elToRemove.parentNode, false);\n }\n }\n }\n }\n\n if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {\n if (morphedNode.actualize) {\n morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);\n }\n // If we had to swap out the from node with a new node because the old\n // node was not compatible with the target node then we need to\n // replace the old DOM node in the original DOM tree. This is only\n // possible if the original DOM node was part of a DOM tree which\n // we know is the case if it has a parent node.\n fromNode.parentNode.replaceChild(morphedNode, fromNode);\n }\n\n return morphedNode;\n };\n}\n\nvar morphdom = morphdomFactory(morphAttrs);\n\nexport default morphdom;\n", "import {\n PHX_COMPONENT,\n PHX_DISABLE_WITH,\n PHX_FEEDBACK_FOR,\n PHX_PRUNE,\n PHX_ROOT_ID,\n PHX_SESSION,\n PHX_SKIP,\n PHX_STATIC,\n PHX_TRIGGER_ACTION,\n PHX_UPDATE\n} from \"./constants\"\n\nimport {\n detectDuplicateIds,\n isCid\n} from \"./utils\"\n\nimport DOM from \"./dom\"\nimport DOMPostMorphRestorer from \"./dom_post_morph_restorer\"\nimport morphdom from \"morphdom\"\n\nexport default class DOMPatch {\n static patchEl(fromEl, toEl, activeElement){\n morphdom(fromEl, toEl, {\n childrenOnly: false,\n onBeforeElUpdated: (fromEl, toEl) => {\n if(activeElement && activeElement.isSameNode(fromEl) && DOM.isFormInput(fromEl)){\n DOM.mergeFocusedInput(fromEl, toEl)\n return false\n }\n }\n })\n }\n\n constructor(view, container, id, html, targetCID){\n this.view = view\n this.liveSocket = view.liveSocket\n this.container = container\n this.id = id\n this.rootID = view.root.id\n this.html = html\n this.targetCID = targetCID\n this.cidPatch = isCid(this.targetCID)\n this.callbacks = {\n beforeadded: [], beforeupdated: [], beforephxChildAdded: [],\n afteradded: [], afterupdated: [], afterdiscarded: [], afterphxChildAdded: [],\n aftertransitionsDiscarded: []\n }\n }\n\n before(kind, callback){ this.callbacks[`before${kind}`].push(callback) }\n after(kind, callback){ this.callbacks[`after${kind}`].push(callback) }\n\n trackBefore(kind, ...args){\n this.callbacks[`before${kind}`].forEach(callback => callback(...args))\n }\n\n trackAfter(kind, ...args){\n this.callbacks[`after${kind}`].forEach(callback => callback(...args))\n }\n\n markPrunableContentForRemoval(){\n DOM.all(this.container, \"[phx-update=append] > *, [phx-update=prepend] > *\", el => {\n el.setAttribute(PHX_PRUNE, \"\")\n })\n }\n\n perform(){\n let {view, liveSocket, container, html} = this\n let targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container\n if(this.isCIDPatch() && !targetContainer){ return }\n\n let focused = liveSocket.getActiveElement()\n let {selectionStart, selectionEnd} = focused && DOM.hasSelectionRange(focused) ? focused : {}\n let phxUpdate = liveSocket.binding(PHX_UPDATE)\n let phxFeedbackFor = liveSocket.binding(PHX_FEEDBACK_FOR)\n let disableWith = liveSocket.binding(PHX_DISABLE_WITH)\n let phxTriggerExternal = liveSocket.binding(PHX_TRIGGER_ACTION)\n let phxRemove = liveSocket.binding(\"remove\")\n let added = []\n let updates = []\n let appendPrependUpdates = []\n let pendingRemoves = []\n let externalFormTriggered = null\n\n let diffHTML = liveSocket.time(\"premorph container prep\", () => {\n return this.buildDiffHTML(container, html, phxUpdate, targetContainer)\n })\n\n this.trackBefore(\"added\", container)\n this.trackBefore(\"updated\", container, container)\n\n liveSocket.time(\"morphdom\", () => {\n morphdom(targetContainer, diffHTML, {\n childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,\n getNodeKey: (node) => {\n return DOM.isPhxDestroyed(node) ? null : node.id\n },\n onBeforeNodeAdded: (el) => {\n this.trackBefore(\"added\", el)\n return el\n },\n onNodeAdded: (el) => {\n // hack to fix Safari handling of img srcset and video tags\n if(el instanceof HTMLImageElement && el.srcset){\n el.srcset = el.srcset\n } else if(el instanceof HTMLVideoElement && el.autoplay){\n el.play()\n }\n if(DOM.isNowTriggerFormExternal(el, phxTriggerExternal)){\n externalFormTriggered = el\n }\n //input handling\n DOM.discardError(targetContainer, el, phxFeedbackFor)\n // nested view handling\n if((DOM.isPhxChild(el) && view.ownsElement(el)) || DOM.isPhxSticky(el) && view.ownsElement(el.parentNode)){\n this.trackAfter(\"phxChildAdded\", el)\n }\n added.push(el)\n },\n onNodeDiscarded: (el) => {\n // nested view handling\n if(DOM.isPhxChild(el) || DOM.isPhxSticky(el)){ liveSocket.destroyViewByEl(el) }\n this.trackAfter(\"discarded\", el)\n },\n onBeforeNodeDiscarded: (el) => {\n if(el.getAttribute && el.getAttribute(PHX_PRUNE) !== null){ return true }\n if(el.parentNode !== null && DOM.isPhxUpdate(el.parentNode, phxUpdate, [\"append\", \"prepend\"]) && el.id){ return false }\n if(el.getAttribute && el.getAttribute(phxRemove)){\n pendingRemoves.push(el)\n return false\n }\n if(this.skipCIDSibling(el)){ return false }\n return true\n },\n onElUpdated: (el) => {\n if(DOM.isNowTriggerFormExternal(el, phxTriggerExternal)){\n externalFormTriggered = el\n }\n updates.push(el)\n },\n onBeforeElUpdated: (fromEl, toEl) => {\n DOM.cleanChildNodes(toEl, phxUpdate)\n if(this.skipCIDSibling(toEl)){ return false }\n if(DOM.isPhxSticky(fromEl)){ return false }\n if(DOM.isIgnored(fromEl, phxUpdate)){\n this.trackBefore(\"updated\", fromEl, toEl)\n DOM.mergeAttrs(fromEl, toEl, {isIgnored: true})\n updates.push(fromEl)\n DOM.applyStickyOperations(fromEl)\n return false\n }\n if(fromEl.type === \"number\" && (fromEl.validity && fromEl.validity.badInput)){ return false }\n if(!DOM.syncPendingRef(fromEl, toEl, disableWith)){\n if(DOM.isUploadInput(fromEl)){\n this.trackBefore(\"updated\", fromEl, toEl)\n updates.push(fromEl)\n }\n DOM.applyStickyOperations(fromEl)\n return false\n }\n\n // nested view handling\n if(DOM.isPhxChild(toEl)){\n let prevSession = fromEl.getAttribute(PHX_SESSION)\n DOM.mergeAttrs(fromEl, toEl, {exclude: [PHX_STATIC]})\n if(prevSession !== \"\"){ fromEl.setAttribute(PHX_SESSION, prevSession) }\n fromEl.setAttribute(PHX_ROOT_ID, this.rootID)\n DOM.applyStickyOperations(fromEl)\n return false\n }\n\n // input handling\n DOM.copyPrivates(toEl, fromEl)\n DOM.discardError(targetContainer, toEl, phxFeedbackFor)\n\n let isFocusedFormEl = focused && fromEl.isSameNode(focused) && DOM.isFormInput(fromEl)\n if(isFocusedFormEl){\n this.trackBefore(\"updated\", fromEl, toEl)\n DOM.mergeFocusedInput(fromEl, toEl)\n DOM.syncAttrsToProps(fromEl)\n updates.push(fromEl)\n DOM.applyStickyOperations(fromEl)\n return false\n } else {\n if(DOM.isPhxUpdate(toEl, phxUpdate, [\"append\", \"prepend\"])){\n appendPrependUpdates.push(new DOMPostMorphRestorer(fromEl, toEl, toEl.getAttribute(phxUpdate)))\n }\n DOM.syncAttrsToProps(toEl)\n DOM.applyStickyOperations(toEl)\n this.trackBefore(\"updated\", fromEl, toEl)\n return true\n }\n }\n })\n })\n\n if(liveSocket.isDebugEnabled()){ detectDuplicateIds() }\n\n if(appendPrependUpdates.length > 0){\n liveSocket.time(\"post-morph append/prepend restoration\", () => {\n appendPrependUpdates.forEach(update => update.perform())\n })\n }\n\n liveSocket.silenceEvents(() => DOM.restoreFocus(focused, selectionStart, selectionEnd))\n DOM.dispatchEvent(document, \"phx:update\")\n added.forEach(el => this.trackAfter(\"added\", el))\n updates.forEach(el => this.trackAfter(\"updated\", el))\n\n if(pendingRemoves.length > 0){\n liveSocket.transitionRemoves(pendingRemoves)\n liveSocket.requestDOMUpdate(() => {\n pendingRemoves.forEach(el => {\n let child = DOM.firstPhxChild(el)\n if(child){ liveSocket.destroyViewByEl(child) }\n el.remove()\n })\n this.trackAfter(\"transitionsDiscarded\", pendingRemoves)\n })\n }\n\n if(externalFormTriggered){\n liveSocket.disconnect()\n externalFormTriggered.submit()\n }\n return true\n }\n\n isCIDPatch(){ return this.cidPatch }\n\n skipCIDSibling(el){\n return el.nodeType === Node.ELEMENT_NODE && el.getAttribute(PHX_SKIP) !== null\n }\n\n targetCIDContainer(html){\n if(!this.isCIDPatch()){ return }\n let [first, ...rest] = DOM.findComponentNodeList(this.container, this.targetCID)\n if(rest.length === 0 && DOM.childNodeLength(html) === 1){\n return first\n } else {\n return first && first.parentNode\n }\n }\n\n // builds HTML for morphdom patch\n // - for full patches of LiveView or a component with a single\n // root node, simply returns the HTML\n // - for patches of a component with multiple root nodes, the\n // parent node becomes the target container and non-component\n // siblings are marked as skip.\n buildDiffHTML(container, html, phxUpdate, targetContainer){\n let isCIDPatch = this.isCIDPatch()\n let isCIDWithSingleRoot = isCIDPatch && targetContainer.getAttribute(PHX_COMPONENT) === this.targetCID.toString()\n if(!isCIDPatch || isCIDWithSingleRoot){\n return html\n } else {\n // component patch with multiple CID roots\n let diffContainer = null\n let template = document.createElement(\"template\")\n diffContainer = DOM.cloneNode(targetContainer)\n let [firstComponent, ...rest] = DOM.findComponentNodeList(diffContainer, this.targetCID)\n template.innerHTML = html\n rest.forEach(el => el.remove())\n Array.from(diffContainer.childNodes).forEach(child => {\n // we can only skip trackable nodes with an ID\n if(child.id && child.nodeType === Node.ELEMENT_NODE && child.getAttribute(PHX_COMPONENT) !== this.targetCID.toString()){\n child.setAttribute(PHX_SKIP, \"\")\n child.innerHTML = \"\"\n }\n })\n Array.from(template.content.childNodes).forEach(el => diffContainer.insertBefore(el, firstComponent))\n firstComponent.remove()\n return diffContainer.outerHTML\n }\n }\n}\n", "import {\n COMPONENTS,\n DYNAMICS,\n TEMPLATES,\n EVENTS,\n PHX_COMPONENT,\n PHX_SKIP,\n REPLY,\n STATIC,\n TITLE\n} from \"./constants\"\n\nimport {\n isObject,\n logError,\n isCid,\n} from \"./utils\"\n\nexport default class Rendered {\n static extract(diff){\n let {[REPLY]: reply, [EVENTS]: events, [TITLE]: title} = diff\n delete diff[REPLY]\n delete diff[EVENTS]\n delete diff[TITLE]\n return {diff, title, reply: reply || null, events: events || []}\n }\n\n constructor(viewId, rendered){\n this.viewId = viewId\n this.rendered = {}\n this.mergeDiff(rendered)\n }\n\n parentViewId(){ return this.viewId }\n\n toString(onlyCids){\n return this.recursiveToString(this.rendered, this.rendered[COMPONENTS], onlyCids)\n }\n\n recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids){\n onlyCids = onlyCids ? new Set(onlyCids) : null\n let output = {buffer: \"\", components: components, onlyCids: onlyCids}\n this.toOutputBuffer(rendered, null, output)\n return output.buffer\n }\n\n componentCIDs(diff){ return Object.keys(diff[COMPONENTS] || {}).map(i => parseInt(i)) }\n\n isComponentOnlyDiff(diff){\n if(!diff[COMPONENTS]){ return false }\n return Object.keys(diff).length === 1\n }\n\n getComponent(diff, cid){ return diff[COMPONENTS][cid] }\n\n mergeDiff(diff){\n let newc = diff[COMPONENTS]\n let cache = {}\n delete diff[COMPONENTS]\n this.rendered = this.mutableMerge(this.rendered, diff)\n this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {}\n\n if(newc){\n let oldc = this.rendered[COMPONENTS]\n\n for(let cid in newc){\n newc[cid] = this.cachedFindComponent(cid, newc[cid], oldc, newc, cache)\n }\n\n for(let cid in newc){ oldc[cid] = newc[cid] }\n diff[COMPONENTS] = newc\n }\n }\n\n cachedFindComponent(cid, cdiff, oldc, newc, cache){\n if(cache[cid]){\n return cache[cid]\n } else {\n let ndiff, stat, scid = cdiff[STATIC]\n\n if(isCid(scid)){\n let tdiff\n\n if(scid > 0){\n tdiff = this.cachedFindComponent(scid, newc[scid], oldc, newc, cache)\n } else {\n tdiff = oldc[-scid]\n }\n\n stat = tdiff[STATIC]\n ndiff = this.cloneMerge(tdiff, cdiff)\n ndiff[STATIC] = stat\n } else {\n ndiff = cdiff[STATIC] !== undefined ? cdiff : this.cloneMerge(oldc[cid] || {}, cdiff)\n }\n\n cache[cid] = ndiff\n return ndiff\n }\n }\n\n mutableMerge(target, source){\n if(source[STATIC] !== undefined){\n return source\n } else {\n this.doMutableMerge(target, source)\n return target\n }\n }\n\n doMutableMerge(target, source){\n for(let key in source){\n let val = source[key]\n let targetVal = target[key]\n if(isObject(val) && val[STATIC] === undefined && isObject(targetVal)){\n this.doMutableMerge(targetVal, val)\n } else {\n target[key] = val\n }\n }\n }\n\n cloneMerge(target, source){\n let merged = {...target, ...source}\n for(let key in merged){\n let val = source[key]\n let targetVal = target[key]\n if(isObject(val) && val[STATIC] === undefined && isObject(targetVal)){\n merged[key] = this.cloneMerge(targetVal, val)\n }\n }\n return merged\n }\n\n componentToString(cid){ return this.recursiveCIDToString(this.rendered[COMPONENTS], cid) }\n\n pruneCIDs(cids){\n cids.forEach(cid => delete this.rendered[COMPONENTS][cid])\n }\n\n // private\n\n get(){ return this.rendered }\n\n isNewFingerprint(diff = {}){ return !!diff[STATIC] }\n\n templateStatic(part, templates){\n if(typeof (part) === \"number\") {\n return templates[part]\n } else {\n return part\n }\n }\n\n toOutputBuffer(rendered, templates, output){\n if(rendered[DYNAMICS]){ return this.comprehensionToBuffer(rendered, templates, output) }\n let {[STATIC]: statics} = rendered\n statics = this.templateStatic(statics, templates)\n\n output.buffer += statics[0]\n for(let i = 1; i < statics.length; i++){\n this.dynamicToBuffer(rendered[i - 1], templates, output)\n output.buffer += statics[i]\n }\n }\n\n comprehensionToBuffer(rendered, templates, output){\n let {[DYNAMICS]: dynamics, [STATIC]: statics} = rendered\n statics = this.templateStatic(statics, templates)\n let compTemplates = templates || rendered[TEMPLATES]\n\n for(let d = 0; d < dynamics.length; d++){\n let dynamic = dynamics[d]\n output.buffer += statics[0]\n for(let i = 1; i < statics.length; i++){\n this.dynamicToBuffer(dynamic[i - 1], compTemplates, output)\n output.buffer += statics[i]\n }\n }\n }\n\n dynamicToBuffer(rendered, templates, output){\n if(typeof (rendered) === \"number\"){\n output.buffer += this.recursiveCIDToString(output.components, rendered, output.onlyCids)\n } else if(isObject(rendered)){\n this.toOutputBuffer(rendered, templates, output)\n } else {\n output.buffer += rendered\n }\n }\n\n recursiveCIDToString(components, cid, onlyCids){\n let component = components[cid] || logError(`no component for CID ${cid}`, components)\n let template = document.createElement(\"template\")\n template.innerHTML = this.recursiveToString(component, components, onlyCids)\n let container = template.content\n let skip = onlyCids && !onlyCids.has(cid)\n\n let [hasChildNodes, hasChildComponents] =\n Array.from(container.childNodes).reduce(([hasNodes, hasComponents], child, i) => {\n if(child.nodeType === Node.ELEMENT_NODE){\n if(child.getAttribute(PHX_COMPONENT)){\n return [hasNodes, true]\n }\n child.setAttribute(PHX_COMPONENT, cid)\n if(!child.id){ child.id = `${this.parentViewId()}-${cid}-${i}` }\n if(skip){\n child.setAttribute(PHX_SKIP, \"\")\n child.innerHTML = \"\"\n }\n return [true, hasComponents]\n } else {\n if(child.nodeValue.trim() !== \"\"){\n logError(\"only HTML element tags are allowed at the root of components.\\n\\n\" +\n `got: \"${child.nodeValue.trim()}\"\\n\\n` +\n \"within:\\n\", template.innerHTML.trim())\n child.replaceWith(this.createSpan(child.nodeValue, cid))\n return [true, hasComponents]\n } else {\n child.remove()\n return [hasNodes, hasComponents]\n }\n }\n }, [false, false])\n\n if(!hasChildNodes && !hasChildComponents){\n logError(\"expected at least one HTML element tag inside a component, but the component is empty:\\n\",\n template.innerHTML.trim())\n return this.createSpan(\"\", cid).outerHTML\n } else if(!hasChildNodes && hasChildComponents){\n logError(\"expected at least one HTML element tag directly inside a component, but only subcomponents were found. A component must render at least one HTML tag directly inside itself.\",\n template.innerHTML.trim())\n return template.innerHTML\n } else {\n return template.innerHTML\n }\n }\n\n createSpan(text, cid){\n let span = document.createElement(\"span\")\n span.innerText = text\n span.setAttribute(PHX_COMPONENT, cid)\n return span\n }\n}\n", "let viewHookID = 1\nexport default class ViewHook {\n static makeID(){ return viewHookID++ }\n static elementID(el){ return el.phxHookId }\n\n constructor(view, el, callbacks){\n this.__view = view\n this.liveSocket = view.liveSocket\n this.__callbacks = callbacks\n this.__listeners = new Set()\n this.__isDisconnected = false\n this.el = el\n this.el.phxHookId = this.constructor.makeID()\n for(let key in this.__callbacks){ this[key] = this.__callbacks[key] }\n }\n\n __mounted(){ this.mounted && this.mounted() }\n __updated(){ this.updated && this.updated() }\n __beforeUpdate(){ this.beforeUpdate && this.beforeUpdate() }\n __destroyed(){ this.destroyed && this.destroyed() }\n __reconnected(){\n if(this.__isDisconnected){\n this.__isDisconnected = false\n this.reconnected && this.reconnected()\n }\n }\n __disconnected(){\n this.__isDisconnected = true\n this.disconnected && this.disconnected()\n }\n\n pushEvent(event, payload = {}, onReply = function (){ }){\n return this.__view.pushHookEvent(null, event, payload, onReply)\n }\n\n pushEventTo(phxTarget, event, payload = {}, onReply = function (){ }){\n return this.__view.withinTargets(phxTarget, (view, targetCtx) => {\n return view.pushHookEvent(targetCtx, event, payload, onReply)\n })\n }\n\n handleEvent(event, callback){\n let callbackRef = (customEvent, bypass) => bypass ? event : callback(customEvent.detail)\n window.addEventListener(`phx:${event}`, callbackRef)\n this.__listeners.add(callbackRef)\n return callbackRef\n }\n\n removeHandleEvent(callbackRef){\n let event = callbackRef(null, true)\n window.removeEventListener(`phx:${event}`, callbackRef)\n this.__listeners.delete(callbackRef)\n }\n\n upload(name, files){\n return this.__view.dispatchUploads(name, files)\n }\n\n uploadTo(phxTarget, name, files){\n return this.__view.withinTargets(phxTarget, view => view.dispatchUploads(name, files))\n }\n\n __cleanup__(){\n this.__listeners.forEach(callbackRef => this.removeHandleEvent(callbackRef))\n }\n}\n", "import DOM from \"./dom\"\n\nlet JS = {\n exec(eventType, phxEvent, view, sourceEl, defaults){\n let [defaultKind, defaultArgs] = defaults || [null, {}]\n let commands = phxEvent.charAt(0) === \"[\" ?\n JSON.parse(phxEvent) : [[defaultKind, defaultArgs]]\n\n commands.forEach(([kind, args]) => {\n if(kind === defaultKind && defaultArgs.data){\n args.data = Object.assign(args.data || {}, defaultArgs.data)\n }\n this.filterToEls(sourceEl, args).forEach(el => {\n this[`exec_${kind}`](eventType, phxEvent, view, sourceEl, el, args)\n })\n })\n },\n\n isVisible(el){\n return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length > 0)\n },\n\n // private\n\n // commands\n\n exec_dispatch(eventType, phxEvent, view, sourceEl, el, {to, event, detail, bubbles}){\n detail = detail || {}\n detail.dispatcher = sourceEl\n DOM.dispatchEvent(el, event, {detail, bubbles})\n },\n\n exec_push(eventType, phxEvent, view, sourceEl, el, args){\n if(!view.isConnected()){ return }\n\n let {event, data, target, page_loading, loading, value, dispatcher} = args\n let pushOpts = {loading, value, target, page_loading: !!page_loading}\n let targetSrc = eventType === \"change\" && dispatcher ? dispatcher : sourceEl\n let phxTarget = target || targetSrc.getAttribute(view.binding(\"target\")) || targetSrc\n view.withinTargets(phxTarget, (targetView, targetCtx) => {\n if(eventType === \"change\"){\n let {newCid, _target, callback} = args\n _target = _target || (sourceEl instanceof HTMLInputElement ? sourceEl.name : undefined)\n if(_target){ pushOpts._target = _target }\n targetView.pushInput(sourceEl, targetCtx, newCid, event || phxEvent, pushOpts, callback)\n } else if(eventType === \"submit\"){\n targetView.submitForm(sourceEl, targetCtx, event || phxEvent, pushOpts)\n } else {\n targetView.pushEvent(eventType, sourceEl, targetCtx, event || phxEvent, data, pushOpts)\n }\n })\n },\n\n exec_add_class(eventType, phxEvent, view, sourceEl, el, {names, transition, time}){\n this.addOrRemoveClasses(el, names, [], transition, time, view)\n },\n\n exec_remove_class(eventType, phxEvent, view, sourceEl, el, {names, transition, time}){\n this.addOrRemoveClasses(el, [], names, transition, time, view)\n },\n\n exec_transition(eventType, phxEvent, view, sourceEl, el, {time, transition}){\n let [transition_start, running, transition_end] = transition\n let onStart = () => this.addOrRemoveClasses(el, transition_start.concat(running), [])\n let onDone = () => this.addOrRemoveClasses(el, transition_end, transition_start.concat(running))\n view.transition(time, onStart, onDone)\n },\n\n exec_toggle(eventType, phxEvent, view, sourceEl, el, {display, ins, outs, time}){\n this.toggle(eventType, view, el, display, ins, outs, time)\n },\n\n exec_show(eventType, phxEvent, view, sourceEl, el, {display, transition, time}){\n this.show(eventType, view, el, display, transition, time)\n },\n\n exec_hide(eventType, phxEvent, view, sourceEl, el, {display, transition, time}){\n this.hide(eventType, view, el, display, transition, time)\n },\n\n exec_set_attr(eventType, phxEvent, view, sourceEl, el, {attr: [attr, val]}){\n this.setOrRemoveAttrs(el, [[attr, val]], [])\n },\n\n exec_remove_attr(eventType, phxEvent, view, sourceEl, el, {attr}){\n this.setOrRemoveAttrs(el, [], [attr])\n },\n\n // utils for commands\n\n show(eventType, view, el, display, transition, time){\n if(!this.isVisible(el)){\n this.toggle(eventType, view, el, display, transition, null, time)\n }\n },\n\n hide(eventType, view, el, display, transition, time){\n if(this.isVisible(el)){\n this.toggle(eventType, view, el, display, null, transition, time)\n }\n },\n\n toggle(eventType, view, el, display, ins, outs, time){\n let [inClasses, inStartClasses, inEndClasses] = ins || [[], [], []]\n let [outClasses, outStartClasses, outEndClasses] = outs || [[], [], []]\n if(inClasses.length > 0 || outClasses.length > 0){\n if(this.isVisible(el)){\n let onStart = () => {\n this.addOrRemoveClasses(el, outStartClasses, inClasses.concat(inStartClasses).concat(inEndClasses))\n window.requestAnimationFrame(() => {\n this.addOrRemoveClasses(el, outClasses, [])\n window.requestAnimationFrame(() => this.addOrRemoveClasses(el, outEndClasses, outStartClasses))\n })\n }\n el.dispatchEvent(new Event(\"phx:hide-start\"))\n view.transition(time, onStart, () => {\n this.addOrRemoveClasses(el, [], outClasses.concat(outEndClasses))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = \"none\")\n el.dispatchEvent(new Event(\"phx:hide-end\"))\n })\n } else {\n if(eventType === \"remove\"){ return }\n let onStart = () => {\n this.addOrRemoveClasses(el, inStartClasses, outClasses.concat(outStartClasses).concat(outEndClasses))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = (display || \"block\"))\n window.requestAnimationFrame(() => {\n this.addOrRemoveClasses(el, inClasses, [])\n window.requestAnimationFrame(() => this.addOrRemoveClasses(el, inEndClasses, inStartClasses))\n })\n }\n el.dispatchEvent(new Event(\"phx:show-start\"))\n view.transition(time, onStart, () => {\n this.addOrRemoveClasses(el, [], inClasses.concat(inEndClasses))\n el.dispatchEvent(new Event(\"phx:show-end\"))\n })\n }\n } else {\n if(this.isVisible(el)){\n window.requestAnimationFrame(() => {\n el.dispatchEvent(new Event(\"phx:hide-start\"))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = \"none\")\n el.dispatchEvent(new Event(\"phx:hide-end\"))\n })\n } else {\n window.requestAnimationFrame(() => {\n el.dispatchEvent(new Event(\"phx:show-start\"))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = display || \"block\")\n el.dispatchEvent(new Event(\"phx:show-end\"))\n })\n }\n }\n },\n\n addOrRemoveClasses(el, adds, removes, transition, time, view){\n let [transition_run, transition_start, transition_end] = transition || [[], [], []]\n if(transition_run.length > 0){\n let onStart = () => this.addOrRemoveClasses(el, transition_start.concat(transition_run), [])\n let onDone = () => this.addOrRemoveClasses(el, adds.concat(transition_end), removes.concat(transition_run).concat(transition_start))\n return view.transition(time, onStart, onDone)\n }\n window.requestAnimationFrame(() => {\n let [prevAdds, prevRemoves] = DOM.getSticky(el, \"classes\", [[], []])\n let keepAdds = adds.filter(name => prevAdds.indexOf(name) < 0 && !el.classList.contains(name))\n let keepRemoves = removes.filter(name => prevRemoves.indexOf(name) < 0 && el.classList.contains(name))\n let newAdds = prevAdds.filter(name => removes.indexOf(name) < 0).concat(keepAdds)\n let newRemoves = prevRemoves.filter(name => adds.indexOf(name) < 0).concat(keepRemoves)\n\n DOM.putSticky(el, \"classes\", currentEl => {\n currentEl.classList.remove(...newRemoves)\n currentEl.classList.add(...newAdds)\n return [newAdds, newRemoves]\n })\n })\n },\n\n setOrRemoveAttrs(el, sets, removes){\n let [prevSets, prevRemoves] = DOM.getSticky(el, \"attrs\", [[], []])\n\n let alteredAttrs = sets.map(([attr, _val]) => attr).concat(removes);\n let newSets = prevSets.filter(([attr, _val]) => !alteredAttrs.includes(attr)).concat(sets);\n let newRemoves = prevRemoves.filter((attr) => !alteredAttrs.includes(attr)).concat(removes);\n\n DOM.putSticky(el, \"attrs\", currentEl => {\n newRemoves.forEach(attr => currentEl.removeAttribute(attr))\n newSets.forEach(([attr, val]) => currentEl.setAttribute(attr, val))\n return [newSets, newRemoves]\n })\n },\n\n hasAllClasses(el, classes){ return classes.every(name => el.classList.contains(name)) },\n\n isToggledOut(el, outClasses){\n return !this.isVisible(el) || this.hasAllClasses(el, outClasses)\n },\n\n filterToEls(sourceEl, {to}){\n return to ? DOM.all(document, to) : [sourceEl]\n }\n}\n\nexport default JS\n", "import {\n BEFORE_UNLOAD_LOADER_TIMEOUT,\n CHECKABLE_INPUTS,\n CONSECUTIVE_RELOADS,\n PHX_AUTO_RECOVER,\n PHX_COMPONENT,\n PHX_CONNECTED_CLASS,\n PHX_DISABLE_WITH,\n PHX_DISABLE_WITH_RESTORE,\n PHX_DISABLED,\n PHX_DISCONNECTED_CLASS,\n PHX_EVENT_CLASSES,\n PHX_ERROR_CLASS,\n PHX_FEEDBACK_FOR,\n PHX_HAS_SUBMITTED,\n PHX_HOOK,\n PHX_PAGE_LOADING,\n PHX_PARENT_ID,\n PHX_PROGRESS,\n PHX_READONLY,\n PHX_REF,\n PHX_REF_SRC,\n PHX_ROOT_ID,\n PHX_SESSION,\n PHX_STATIC,\n PHX_TRACK_STATIC,\n PHX_TRACK_UPLOADS,\n PHX_UPDATE,\n PHX_UPLOAD_REF,\n PHX_VIEW_SELECTOR,\n PUSH_TIMEOUT,\n PHX_MAIN,\n} from \"./constants\"\n\nimport {\n clone,\n closestPhxBinding,\n isEmpty,\n isEqualObj,\n logError,\n maybe,\n isCid,\n} from \"./utils\"\n\nimport Browser from \"./browser\"\nimport DOM from \"./dom\"\nimport DOMPatch from \"./dom_patch\"\nimport LiveUploader from \"./live_uploader\"\nimport Rendered from \"./rendered\"\nimport ViewHook from \"./view_hook\"\nimport JS from \"./js\"\n\nlet serializeForm = (form, meta, onlyNames = []) => {\n let formData = new FormData(form)\n let toRemove = []\n\n formData.forEach((val, key, _index) => {\n if(val instanceof File){ toRemove.push(key) }\n })\n\n // Cleanup after building fileData\n toRemove.forEach(key => formData.delete(key))\n\n let params = new URLSearchParams()\n for(let [key, val] of formData.entries()){\n if(onlyNames.length === 0 || onlyNames.indexOf(key) >= 0){\n params.append(key, val)\n }\n }\n for(let metaKey in meta){ params.append(metaKey, meta[metaKey]) }\n\n return params.toString()\n}\n\nexport default class View {\n constructor(el, liveSocket, parentView, flash){\n this.liveSocket = liveSocket\n this.flash = flash\n this.parent = parentView\n this.root = parentView ? parentView.root : this\n this.el = el\n this.id = this.el.id\n this.ref = 0\n this.childJoins = 0\n this.loaderTimer = null\n this.pendingDiffs = []\n this.pruningCIDs = []\n this.redirect = false\n this.href = null\n this.joinCount = this.parent ? this.parent.joinCount - 1 : 0\n this.joinPending = true\n this.destroyed = false\n this.joinCallback = function(onDone){ onDone && onDone() }\n this.stopCallback = function(){ }\n this.pendingJoinOps = this.parent ? null : []\n this.viewHooks = {}\n this.uploaders = {}\n this.formSubmits = []\n this.children = this.parent ? null : {}\n this.root.children[this.id] = {}\n this.channel = this.liveSocket.channel(`lv:${this.id}`, () => {\n return {\n redirect: this.redirect ? this.href : undefined,\n url: this.redirect ? undefined : this.href || undefined,\n params: this.connectParams(),\n session: this.getSession(),\n static: this.getStatic(),\n flash: this.flash\n }\n })\n this.showLoader(this.liveSocket.loaderTimeout)\n this.bindChannel()\n }\n\n setHref(href){ this.href = href }\n\n setRedirect(href){\n this.redirect = true\n this.href = href\n }\n\n isMain(){ return this.el.hasAttribute(PHX_MAIN) }\n\n connectParams(){\n let params = this.liveSocket.params(this.el)\n let manifest =\n DOM.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`)\n .map(node => node.src || node.href).filter(url => typeof (url) === \"string\")\n\n if(manifest.length > 0){ params[\"_track_static\"] = manifest }\n params[\"_mounts\"] = this.joinCount\n\n return params\n }\n\n isConnected(){ return this.channel.canPush() }\n\n getSession(){ return this.el.getAttribute(PHX_SESSION) }\n\n getStatic(){\n let val = this.el.getAttribute(PHX_STATIC)\n return val === \"\" ? null : val\n }\n\n destroy(callback = function (){ }){\n this.destroyAllChildren()\n this.destroyed = true\n delete this.root.children[this.id]\n if(this.parent){ delete this.root.children[this.parent.id][this.id] }\n clearTimeout(this.loaderTimer)\n let onFinished = () => {\n callback()\n for(let id in this.viewHooks){\n this.destroyHook(this.viewHooks[id])\n }\n }\n\n DOM.markPhxChildDestroyed(this.el)\n\n this.log(\"destroyed\", () => [\"the child has been removed from the parent\"])\n this.channel.leave()\n .receive(\"ok\", onFinished)\n .receive(\"error\", onFinished)\n .receive(\"timeout\", onFinished)\n }\n\n setContainerClasses(...classes){\n this.el.classList.remove(\n PHX_CONNECTED_CLASS,\n PHX_DISCONNECTED_CLASS,\n PHX_ERROR_CLASS\n )\n this.el.classList.add(...classes)\n }\n\n showLoader(timeout){\n clearTimeout(this.loaderTimer)\n if(timeout){\n this.loaderTimer = setTimeout(() => this.showLoader(), timeout)\n } else {\n for(let id in this.viewHooks){ this.viewHooks[id].__disconnected() }\n this.setContainerClasses(PHX_DISCONNECTED_CLASS)\n }\n }\n\n hideLoader(){\n clearTimeout(this.loaderTimer)\n this.setContainerClasses(PHX_CONNECTED_CLASS)\n }\n\n triggerReconnected(){\n for(let id in this.viewHooks){ this.viewHooks[id].__reconnected() }\n }\n\n log(kind, msgCallback){\n this.liveSocket.log(this, kind, msgCallback)\n }\n\n transition(time, onStart, onDone = function(){}){\n this.liveSocket.transition(time, onStart, onDone)\n }\n\n withinTargets(phxTarget, callback){\n if(phxTarget instanceof HTMLElement || phxTarget instanceof SVGElement){\n return this.liveSocket.owner(phxTarget, view => callback(view, phxTarget))\n }\n\n if(isCid(phxTarget)){\n let targets = DOM.findComponentNodeList(this.el, phxTarget)\n if(targets.length === 0){\n logError(`no component found matching phx-target of ${phxTarget}`)\n } else {\n callback(this, parseInt(phxTarget))\n }\n } else {\n let targets = Array.from(document.querySelectorAll(phxTarget))\n if(targets.length === 0){ logError(`nothing found matching the phx-target selector \"${phxTarget}\"`) }\n targets.forEach(target => this.liveSocket.owner(target, view => callback(view, target)))\n }\n }\n\n applyDiff(type, rawDiff, callback){\n this.log(type, () => [\"\", clone(rawDiff)])\n let {diff, reply, events, title} = Rendered.extract(rawDiff)\n if(title){ DOM.putTitle(title) }\n\n callback({diff, reply, events})\n return reply\n }\n\n onJoin(resp){\n let {rendered, container} = resp\n if(container){\n let [tag, attrs] = container\n this.el = DOM.replaceRootContainer(this.el, tag, attrs)\n }\n this.childJoins = 0\n this.joinPending = true\n this.flash = null\n\n Browser.dropLocal(this.liveSocket.localStorage, window.location.pathname, CONSECUTIVE_RELOADS)\n this.applyDiff(\"mount\", rendered, ({diff, events}) => {\n this.rendered = new Rendered(this.id, diff)\n let html = this.renderContainer(null, \"join\")\n this.dropPendingRefs()\n let forms = this.formsForRecovery(html)\n this.joinCount++\n\n if(forms.length > 0){\n forms.forEach(([form, newForm, newCid], i) => {\n this.pushFormRecovery(form, newCid, resp => {\n if(i === forms.length - 1){\n this.onJoinComplete(resp, html, events)\n }\n })\n })\n } else {\n this.onJoinComplete(resp, html, events)\n }\n })\n }\n\n dropPendingRefs(){\n DOM.all(document, `[${PHX_REF_SRC}=\"${this.id}\"][${PHX_REF}]`, el => {\n el.removeAttribute(PHX_REF)\n el.removeAttribute(PHX_REF_SRC)\n })\n }\n\n onJoinComplete({live_patch}, html, events){\n // In order to provide a better experience, we want to join\n // all LiveViews first and only then apply their patches.\n if(this.joinCount > 1 || (this.parent && !this.parent.isJoinPending())){\n return this.applyJoinPatch(live_patch, html, events)\n }\n\n // One downside of this approach is that we need to find phxChildren\n // in the html fragment, instead of directly on the DOM. The fragment\n // also does not include PHX_STATIC, so we need to copy it over from\n // the DOM.\n let newChildren = DOM.findPhxChildrenInFragment(html, this.id).filter(toEl => {\n let fromEl = toEl.id && this.el.querySelector(`[id=\"${toEl.id}\"]`)\n let phxStatic = fromEl && fromEl.getAttribute(PHX_STATIC)\n if(phxStatic){ toEl.setAttribute(PHX_STATIC, phxStatic) }\n return this.joinChild(toEl)\n })\n\n if(newChildren.length === 0){\n if(this.parent){\n this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, events)])\n this.parent.ackJoin(this)\n } else {\n this.onAllChildJoinsComplete()\n this.applyJoinPatch(live_patch, html, events)\n }\n } else {\n this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, events)])\n }\n }\n\n attachTrueDocEl(){\n this.el = DOM.byId(this.id)\n this.el.setAttribute(PHX_ROOT_ID, this.root.id)\n }\n\n applyJoinPatch(live_patch, html, events){\n this.attachTrueDocEl()\n let patch = new DOMPatch(this, this.el, this.id, html, null)\n patch.markPrunableContentForRemoval()\n this.performPatch(patch, false)\n this.joinNewChildren()\n DOM.all(this.el, `[${this.binding(PHX_HOOK)}], [data-phx-${PHX_HOOK}]`, hookEl => {\n let hook = this.addHook(hookEl)\n if(hook){ hook.__mounted() }\n })\n\n this.joinPending = false\n this.liveSocket.dispatchEvents(events)\n this.applyPendingUpdates()\n\n if(live_patch){\n let {kind, to} = live_patch\n this.liveSocket.historyPatch(to, kind)\n }\n this.hideLoader()\n if(this.joinCount > 1){ this.triggerReconnected() }\n this.stopCallback()\n }\n\n triggerBeforeUpdateHook(fromEl, toEl){\n this.liveSocket.triggerDOM(\"onBeforeElUpdated\", [fromEl, toEl])\n let hook = this.getHook(fromEl)\n let isIgnored = hook && DOM.isIgnored(fromEl, this.binding(PHX_UPDATE))\n if(hook && !fromEl.isEqualNode(toEl) && !(isIgnored && isEqualObj(fromEl.dataset, toEl.dataset))){\n hook.__beforeUpdate()\n return hook\n }\n }\n\n performPatch(patch, pruneCids){\n let removedEls = []\n let phxChildrenAdded = false\n let updatedHookIds = new Set()\n\n patch.after(\"added\", el => {\n this.liveSocket.triggerDOM(\"onNodeAdded\", [el])\n\n let newHook = this.addHook(el)\n if(newHook){ newHook.__mounted() }\n })\n\n patch.after(\"phxChildAdded\", el => {\n if(DOM.isPhxSticky(el)){\n this.liveSocket.joinRootViews()\n } else {\n phxChildrenAdded = true\n }\n })\n\n patch.before(\"updated\", (fromEl, toEl) => {\n let hook = this.triggerBeforeUpdateHook(fromEl, toEl)\n if(hook){ updatedHookIds.add(fromEl.id) }\n })\n\n patch.after(\"updated\", el => {\n if(updatedHookIds.has(el.id)){ this.getHook(el).__updated() }\n })\n\n patch.after(\"discarded\", (el) => {\n if(el.nodeType === Node.ELEMENT_NODE){ removedEls.push(el) }\n })\n\n patch.after(\"transitionsDiscarded\", els => this.afterElementsRemoved(els, pruneCids))\n patch.perform()\n this.afterElementsRemoved(removedEls, pruneCids)\n\n return phxChildrenAdded\n }\n\n afterElementsRemoved(elements, pruneCids){\n let destroyedCIDs = []\n elements.forEach(parent => {\n let components = DOM.all(parent, `[${PHX_COMPONENT}]`)\n let hooks = DOM.all(parent, `[${this.binding(PHX_HOOK)}]`)\n components.concat(parent).forEach(el => {\n let cid = this.componentID(el)\n if(isCid(cid) && destroyedCIDs.indexOf(cid) === -1){ destroyedCIDs.push(cid) }\n })\n hooks.concat(parent).forEach(hookEl => {\n let hook = this.getHook(hookEl)\n hook && this.destroyHook(hook)\n })\n })\n // We should not pruneCids on joins. Otherwise, in case of\n // rejoins, we may notify cids that no longer belong to the\n // current LiveView to be removed.\n if(pruneCids){\n this.maybePushComponentsDestroyed(destroyedCIDs)\n }\n }\n\n joinNewChildren(){\n DOM.findPhxChildren(this.el, this.id).forEach(el => this.joinChild(el))\n }\n\n getChildById(id){ return this.root.children[this.id][id] }\n\n getDescendentByEl(el){\n if(el.id === this.id){\n return this\n } else {\n return this.children[el.getAttribute(PHX_PARENT_ID)][el.id]\n }\n }\n\n destroyDescendent(id){\n for(let parentId in this.root.children){\n for(let childId in this.root.children[parentId]){\n if(childId === id){ return this.root.children[parentId][childId].destroy() }\n }\n }\n }\n\n joinChild(el){\n let child = this.getChildById(el.id)\n if(!child){\n let view = new View(el, this.liveSocket, this)\n this.root.children[this.id][view.id] = view\n view.join()\n this.childJoins++\n return true\n }\n }\n\n isJoinPending(){ return this.joinPending }\n\n ackJoin(_child){\n this.childJoins--\n\n if(this.childJoins === 0){\n if(this.parent){\n this.parent.ackJoin(this)\n } else {\n this.onAllChildJoinsComplete()\n }\n }\n }\n\n onAllChildJoinsComplete(){\n this.joinCallback(() => {\n this.pendingJoinOps.forEach(([view, op]) => {\n if(!view.isDestroyed()){ op() }\n })\n this.pendingJoinOps = []\n })\n }\n\n update(diff, events){\n if(this.isJoinPending() || (this.liveSocket.hasPendingLink() && !DOM.isPhxSticky(this.el))){\n return this.pendingDiffs.push({diff, events})\n }\n\n this.rendered.mergeDiff(diff)\n let phxChildrenAdded = false\n\n // When the diff only contains component diffs, then walk components\n // and patch only the parent component containers found in the diff.\n // Otherwise, patch entire LV container.\n if(this.rendered.isComponentOnlyDiff(diff)){\n this.liveSocket.time(\"component patch complete\", () => {\n let parentCids = DOM.findParentCIDs(this.el, this.rendered.componentCIDs(diff))\n parentCids.forEach(parentCID => {\n if(this.componentPatch(this.rendered.getComponent(diff, parentCID), parentCID)){ phxChildrenAdded = true }\n })\n })\n } else if(!isEmpty(diff)){\n this.liveSocket.time(\"full patch complete\", () => {\n let html = this.renderContainer(diff, \"update\")\n let patch = new DOMPatch(this, this.el, this.id, html, null)\n phxChildrenAdded = this.performPatch(patch, true)\n })\n }\n\n this.liveSocket.dispatchEvents(events)\n if(phxChildrenAdded){ this.joinNewChildren() }\n }\n\n renderContainer(diff, kind){\n return this.liveSocket.time(`toString diff (${kind})`, () => {\n let tag = this.el.tagName\n // Don't skip any component in the diff nor any marked as pruned\n // (as they may have been added back)\n let cids = diff ? this.rendered.componentCIDs(diff).concat(this.pruningCIDs) : null\n let html = this.rendered.toString(cids)\n return `<${tag}>${html}</${tag}>`\n })\n }\n\n componentPatch(diff, cid){\n if(isEmpty(diff)) return false\n let html = this.rendered.componentToString(cid)\n let patch = new DOMPatch(this, this.el, this.id, html, cid)\n let childrenAdded = this.performPatch(patch, true)\n return childrenAdded\n }\n\n getHook(el){ return this.viewHooks[ViewHook.elementID(el)] }\n\n addHook(el){\n if(ViewHook.elementID(el) || !el.getAttribute){ return }\n let hookName = el.getAttribute(`data-phx-${PHX_HOOK}`) || el.getAttribute(this.binding(PHX_HOOK))\n if(hookName && !this.ownsElement(el)){ return }\n let callbacks = this.liveSocket.getHookCallbacks(hookName)\n\n if(callbacks){\n if(!el.id){ logError(`no DOM ID for hook \"${hookName}\". Hooks require a unique ID on each element.`, el) }\n let hook = new ViewHook(this, el, callbacks)\n this.viewHooks[ViewHook.elementID(hook.el)] = hook\n return hook\n } else if(hookName !== null){\n logError(`unknown hook found for \"${hookName}\"`, el)\n }\n }\n\n destroyHook(hook){\n hook.__destroyed()\n hook.__cleanup__()\n delete this.viewHooks[ViewHook.elementID(hook.el)]\n }\n\n applyPendingUpdates(){\n this.pendingDiffs.forEach(({diff, events}) => this.update(diff, events))\n this.pendingDiffs = []\n }\n\n onChannel(event, cb){\n this.liveSocket.onChannel(this.channel, event, resp => {\n if(this.isJoinPending()){\n this.root.pendingJoinOps.push([this, () => cb(resp)])\n } else {\n this.liveSocket.requestDOMUpdate(() => cb(resp))\n }\n })\n }\n\n bindChannel(){\n // The diff event should be handled by the regular update operations.\n // All other operations are queued to be applied only after join.\n this.liveSocket.onChannel(this.channel, \"diff\", (rawDiff) => {\n this.liveSocket.requestDOMUpdate(() => {\n this.applyDiff(\"update\", rawDiff, ({diff, events}) => this.update(diff, events))\n })\n })\n this.onChannel(\"redirect\", ({to, flash}) => this.onRedirect({to, flash}))\n this.onChannel(\"live_patch\", (redir) => this.onLivePatch(redir))\n this.onChannel(\"live_redirect\", (redir) => this.onLiveRedirect(redir))\n this.channel.onError(reason => this.onError(reason))\n this.channel.onClose(reason => this.onClose(reason))\n }\n\n destroyAllChildren(){\n for(let id in this.root.children[this.id]){\n this.getChildById(id).destroy()\n }\n }\n\n onLiveRedirect(redir){\n let {to, kind, flash} = redir\n let url = this.expandURL(to)\n this.liveSocket.historyRedirect(url, kind, flash)\n }\n\n onLivePatch(redir){\n let {to, kind} = redir\n this.href = this.expandURL(to)\n this.liveSocket.historyPatch(to, kind)\n }\n\n expandURL(to){\n return to.startsWith(\"/\") ? `${window.location.protocol}//${window.location.host}${to}` : to\n }\n\n onRedirect({to, flash}){ this.liveSocket.redirect(to, flash) }\n\n isDestroyed(){ return this.destroyed }\n\n join(callback){\n if(this.isMain()){\n this.stopCallback = this.liveSocket.withPageLoading({to: this.href, kind: \"initial\"})\n }\n this.joinCallback = (onDone) => {\n onDone = onDone || function(){}\n callback ? callback(this.joinCount, onDone) : onDone()\n }\n this.liveSocket.wrapPush(this, {timeout: false}, () => {\n return this.channel.join()\n .receive(\"ok\", data => {\n if(!this.isDestroyed()){\n this.liveSocket.requestDOMUpdate(() => this.onJoin(data))\n }\n })\n .receive(\"error\", resp => !this.isDestroyed() && this.onJoinError(resp))\n .receive(\"timeout\", () => !this.isDestroyed() && this.onJoinError({reason: \"timeout\"}))\n })\n }\n\n onJoinError(resp){\n if(resp.reason === \"unauthorized\" || resp.reason === \"stale\"){\n this.log(\"error\", () => [\"unauthorized live_redirect. Falling back to page request\", resp])\n return this.onRedirect({to: this.href})\n }\n if(resp.redirect || resp.live_redirect){\n this.joinPending = false\n this.channel.leave()\n }\n if(resp.redirect){ return this.onRedirect(resp.redirect) }\n if(resp.live_redirect){ return this.onLiveRedirect(resp.live_redirect) }\n this.log(\"error\", () => [\"unable to join\", resp])\n if(this.liveSocket.isConnected()){ this.liveSocket.reloadWithJitter(this) }\n }\n\n onClose(reason){\n if(this.isDestroyed()){ return }\n if(this.liveSocket.hasPendingLink() && reason !== \"leave\"){\n return this.liveSocket.reloadWithJitter(this)\n }\n this.destroyAllChildren()\n this.liveSocket.dropActiveElement(this)\n // document.activeElement can be null in Internet Explorer 11\n if(document.activeElement){ document.activeElement.blur() }\n if(this.liveSocket.isUnloaded()){\n this.showLoader(BEFORE_UNLOAD_LOADER_TIMEOUT)\n }\n }\n\n onError(reason){\n this.onClose(reason)\n if(this.liveSocket.isConnected()){ this.log(\"error\", () => [\"view crashed\", reason]) }\n if(!this.liveSocket.isUnloaded()){ this.displayError() }\n }\n\n displayError(){\n if(this.isMain()){ DOM.dispatchEvent(window, \"phx:page-loading-start\", {detail: {to: this.href, kind: \"error\"}}) }\n this.showLoader()\n this.setContainerClasses(PHX_DISCONNECTED_CLASS, PHX_ERROR_CLASS)\n }\n\n pushWithReply(refGenerator, event, payload, onReply = function (){ }){\n if(!this.isConnected()){ return }\n\n let [ref, [el], opts] = refGenerator ? refGenerator() : [null, [], {}]\n let onLoadingDone = function(){ }\n if(opts.page_loading || (el && (el.getAttribute(this.binding(PHX_PAGE_LOADING)) !== null))){\n onLoadingDone = this.liveSocket.withPageLoading({kind: \"element\", target: el})\n }\n\n if(typeof (payload.cid) !== \"number\"){ delete payload.cid }\n return (\n this.liveSocket.wrapPush(this, {timeout: true}, () => {\n return this.channel.push(event, payload, PUSH_TIMEOUT).receive(\"ok\", resp => {\n if(ref !== null){ this.undoRefs(ref) }\n let finish = (hookReply) => {\n if(resp.redirect){ this.onRedirect(resp.redirect) }\n if(resp.live_patch){ this.onLivePatch(resp.live_patch) }\n if(resp.live_redirect){ this.onLiveRedirect(resp.live_redirect) }\n onLoadingDone()\n onReply(resp, hookReply)\n }\n if(resp.diff){\n this.liveSocket.requestDOMUpdate(() => {\n let hookReply = this.applyDiff(\"update\", resp.diff, ({diff, events}) => {\n this.update(diff, events)\n })\n finish(hookReply)\n })\n } else {\n finish(null)\n }\n })\n })\n )\n }\n\n undoRefs(ref){\n DOM.all(document, `[${PHX_REF_SRC}=\"${this.id}\"][${PHX_REF}=\"${ref}\"]`, el => {\n let disabledVal = el.getAttribute(PHX_DISABLED)\n // remove refs\n el.removeAttribute(PHX_REF)\n el.removeAttribute(PHX_REF_SRC)\n // restore inputs\n if(el.getAttribute(PHX_READONLY) !== null){\n el.readOnly = false\n el.removeAttribute(PHX_READONLY)\n }\n if(disabledVal !== null){\n el.disabled = disabledVal === \"true\" ? true : false\n el.removeAttribute(PHX_DISABLED)\n }\n // remove classes\n PHX_EVENT_CLASSES.forEach(className => DOM.removeClass(el, className))\n // restore disables\n let disableRestore = el.getAttribute(PHX_DISABLE_WITH_RESTORE)\n if(disableRestore !== null){\n el.innerText = disableRestore\n el.removeAttribute(PHX_DISABLE_WITH_RESTORE)\n }\n let toEl = DOM.private(el, PHX_REF)\n if(toEl){\n let hook = this.triggerBeforeUpdateHook(el, toEl)\n DOMPatch.patchEl(el, toEl, this.liveSocket.getActiveElement())\n if(hook){ hook.__updated() }\n DOM.deletePrivate(el, PHX_REF)\n }\n })\n }\n\n putRef(elements, event, opts = {}){\n let newRef = this.ref++\n let disableWith = this.binding(PHX_DISABLE_WITH)\n if(opts.loading){ elements = elements.concat(DOM.all(document, opts.loading))}\n\n elements.forEach(el => {\n el.classList.add(`phx-${event}-loading`)\n el.setAttribute(PHX_REF, newRef)\n el.setAttribute(PHX_REF_SRC, this.el.id)\n let disableText = el.getAttribute(disableWith)\n if(disableText !== null){\n if(!el.getAttribute(PHX_DISABLE_WITH_RESTORE)){\n el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.innerText)\n }\n if(disableText !== \"\"){ el.innerText = disableText }\n el.setAttribute(\"disabled\", \"\")\n }\n })\n return [newRef, elements, opts]\n }\n\n componentID(el){\n let cid = el.getAttribute && el.getAttribute(PHX_COMPONENT)\n return cid ? parseInt(cid) : null\n }\n\n targetComponentID(target, targetCtx, opts = {}){\n if(isCid(targetCtx)){ return targetCtx }\n\n let cidOrSelector = target.getAttribute(this.binding(\"target\"))\n if(isCid(cidOrSelector)){\n return parseInt(cidOrSelector)\n } else if(targetCtx && (cidOrSelector !== null || opts.target)){\n return this.closestComponentID(targetCtx)\n } else {\n return null\n }\n }\n\n closestComponentID(targetCtx){\n if(isCid(targetCtx)){\n return targetCtx\n } else if(targetCtx){\n return maybe(targetCtx.closest(`[${PHX_COMPONENT}]`), el => this.ownsElement(el) && this.componentID(el))\n } else {\n return null\n }\n }\n\n pushHookEvent(targetCtx, event, payload, onReply){\n if(!this.isConnected()){\n this.log(\"hook\", () => [\"unable to push hook event. LiveView not connected\", event, payload])\n return false\n }\n let [ref, els, opts] = this.putRef([], \"hook\")\n this.pushWithReply(() => [ref, els, opts], \"event\", {\n type: \"hook\",\n event: event,\n value: payload,\n cid: this.closestComponentID(targetCtx)\n }, (resp, reply) => onReply(reply, ref))\n\n return ref\n }\n\n extractMeta(el, meta, value){\n let prefix = this.binding(\"value-\")\n for(let i = 0; i < el.attributes.length; i++){\n if(!meta){ meta = {} }\n let name = el.attributes[i].name\n if(name.startsWith(prefix)){ meta[name.replace(prefix, \"\")] = el.getAttribute(name) }\n }\n if(el.value !== undefined){\n if(!meta){ meta = {} }\n meta.value = el.value\n\n if(el.tagName === \"INPUT\" && CHECKABLE_INPUTS.indexOf(el.type) >= 0 && !el.checked){\n delete meta.value\n }\n }\n if(value){\n if(!meta){ meta = {} }\n for(let key in value){ meta[key] = value[key] }\n }\n return meta\n }\n\n pushEvent(type, el, targetCtx, phxEvent, meta, opts = {}){\n this.pushWithReply(() => this.putRef([el], type, opts), \"event\", {\n type: type,\n event: phxEvent,\n value: this.extractMeta(el, meta, opts.value),\n cid: this.targetComponentID(el, targetCtx, opts)\n })\n }\n\n pushFileProgress(fileEl, entryRef, progress, onReply = function (){ }){\n this.liveSocket.withinOwners(fileEl.form, (view, targetCtx) => {\n view.pushWithReply(null, \"progress\", {\n event: fileEl.getAttribute(view.binding(PHX_PROGRESS)),\n ref: fileEl.getAttribute(PHX_UPLOAD_REF),\n entry_ref: entryRef,\n progress: progress,\n cid: view.targetComponentID(fileEl.form, targetCtx)\n }, onReply)\n })\n }\n\n pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback){\n let uploads\n let cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx)\n let refGenerator = () => this.putRef([inputEl, inputEl.form], \"change\", opts)\n let formData\n if(inputEl.getAttribute(this.binding(\"change\"))){\n formData = serializeForm(inputEl.form, {_target: opts._target}, [inputEl.name])\n } else {\n formData = serializeForm(inputEl.form, {_target: opts._target})\n }\n if(DOM.isUploadInput(inputEl) && inputEl.files && inputEl.files.length > 0){\n LiveUploader.trackFiles(inputEl, Array.from(inputEl.files))\n }\n uploads = LiveUploader.serializeUploads(inputEl)\n let event = {\n type: \"form\",\n event: phxEvent,\n value: formData,\n uploads: uploads,\n cid: cid\n }\n this.pushWithReply(refGenerator, \"event\", event, resp => {\n DOM.showError(inputEl, this.liveSocket.binding(PHX_FEEDBACK_FOR))\n if(DOM.isUploadInput(inputEl) && inputEl.getAttribute(\"data-phx-auto-upload\") !== null){\n if(LiveUploader.filesAwaitingPreflight(inputEl).length > 0){\n let [ref, _els] = refGenerator()\n this.uploadFiles(inputEl.form, targetCtx, ref, cid, (_uploads) => {\n callback && callback(resp)\n this.triggerAwaitingSubmit(inputEl.form)\n })\n }\n } else {\n callback && callback(resp)\n }\n })\n }\n\n triggerAwaitingSubmit(formEl){\n let awaitingSubmit = this.getScheduledSubmit(formEl)\n if(awaitingSubmit){\n let [_el, _ref, _opts, callback] = awaitingSubmit\n this.cancelSubmit(formEl)\n callback()\n }\n }\n\n getScheduledSubmit(formEl){\n return this.formSubmits.find(([el, _ref, _opts, _callback]) => el.isSameNode(formEl))\n }\n\n scheduleSubmit(formEl, ref, opts, callback){\n if(this.getScheduledSubmit(formEl)){ return true }\n this.formSubmits.push([formEl, ref, opts, callback])\n }\n\n cancelSubmit(formEl){\n this.formSubmits = this.formSubmits.filter(([el, ref, _callback]) => {\n if(el.isSameNode(formEl)){\n this.undoRefs(ref)\n return false\n } else {\n return true\n }\n })\n }\n\n pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply){\n let filterIgnored = el => {\n let userIgnored = closestPhxBinding(el, `${this.binding(PHX_UPDATE)}=ignore`, el.form)\n return !(userIgnored || closestPhxBinding(el, \"data-phx-update=ignore\", el.form))\n }\n let filterDisables = el => {\n return el.hasAttribute(this.binding(PHX_DISABLE_WITH))\n }\n let filterButton = el => el.tagName == \"BUTTON\"\n\n let filterInput = el => [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(el.tagName)\n\n let refGenerator = () => {\n let formElements = Array.from(formEl.elements)\n let disables = formElements.filter(filterDisables)\n let buttons = formElements.filter(filterButton).filter(filterIgnored)\n let inputs = formElements.filter(filterInput).filter(filterIgnored)\n\n buttons.forEach(button => {\n button.setAttribute(PHX_DISABLED, button.disabled)\n button.disabled = true\n })\n inputs.forEach(input => {\n input.setAttribute(PHX_READONLY, input.readOnly)\n input.readOnly = true\n if(input.files){\n input.setAttribute(PHX_DISABLED, input.disabled)\n input.disabled = true\n }\n })\n formEl.setAttribute(this.binding(PHX_PAGE_LOADING), \"\")\n return this.putRef([formEl].concat(disables).concat(buttons).concat(inputs), \"submit\", opts)\n }\n\n let cid = this.targetComponentID(formEl, targetCtx)\n if(LiveUploader.hasUploadsInProgress(formEl)){\n let [ref, _els] = refGenerator()\n let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply)\n return this.scheduleSubmit(formEl, ref, opts, push)\n } else if(LiveUploader.inputsAwaitingPreflight(formEl).length > 0){\n let [ref, els] = refGenerator()\n let proxyRefGen = () => [ref, els, opts]\n this.uploadFiles(formEl, targetCtx, ref, cid, (_uploads) => {\n let formData = serializeForm(formEl, {})\n this.pushWithReply(proxyRefGen, \"event\", {\n type: \"form\",\n event: phxEvent,\n value: formData,\n cid: cid\n }, onReply)\n })\n } else {\n let formData = serializeForm(formEl, {})\n this.pushWithReply(refGenerator, \"event\", {\n type: \"form\",\n event: phxEvent,\n value: formData,\n cid: cid\n }, onReply)\n }\n }\n\n uploadFiles(formEl, targetCtx, ref, cid, onComplete){\n let joinCountAtUpload = this.joinCount\n let inputEls = LiveUploader.activeFileInputs(formEl)\n let numFileInputsInProgress = inputEls.length\n\n // get each file input\n inputEls.forEach(inputEl => {\n let uploader = new LiveUploader(inputEl, this, () => {\n numFileInputsInProgress--\n if(numFileInputsInProgress === 0){ onComplete() }\n });\n\n this.uploaders[inputEl] = uploader\n let entries = uploader.entries().map(entry => entry.toPreflightPayload())\n\n let payload = {\n ref: inputEl.getAttribute(PHX_UPLOAD_REF),\n entries: entries,\n cid: this.targetComponentID(inputEl.form, targetCtx)\n }\n\n this.log(\"upload\", () => [\"sending preflight request\", payload])\n\n this.pushWithReply(null, \"allow_upload\", payload, resp => {\n this.log(\"upload\", () => [\"got preflight response\", resp])\n if(resp.error){\n this.undoRefs(ref)\n let [entry_ref, reason] = resp.error\n this.log(\"upload\", () => [`error for entry ${entry_ref}`, reason])\n } else {\n let onError = (callback) => {\n this.channel.onError(() => {\n if(this.joinCount === joinCountAtUpload){ callback() }\n })\n }\n uploader.initAdapterUpload(resp, onError, this.liveSocket)\n }\n })\n })\n }\n\n dispatchUploads(name, filesOrBlobs){\n let inputs = DOM.findUploadInputs(this.el).filter(el => el.name === name)\n if(inputs.length === 0){ logError(`no live file inputs found matching the name \"${name}\"`) }\n else if(inputs.length > 1){ logError(`duplicate live file inputs found matching the name \"${name}\"`) }\n else { DOM.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, {detail: {files: filesOrBlobs}}) }\n }\n\n pushFormRecovery(form, newCid, callback){\n this.liveSocket.withinOwners(form, (view, targetCtx) => {\n let input = form.elements[0]\n let phxEvent = form.getAttribute(this.binding(PHX_AUTO_RECOVER)) || form.getAttribute(this.binding(\"change\"))\n\n JS.exec(\"change\", phxEvent, view, input, [\"push\", {_target: input.name, newCid: newCid, callback: callback}])\n })\n }\n\n pushLinkPatch(href, targetEl, callback){\n let linkRef = this.liveSocket.setPendingLink(href)\n let refGen = targetEl ? () => this.putRef([targetEl], \"click\") : null\n let fallback = () => this.liveSocket.redirect(window.location.href)\n\n let push = this.pushWithReply(refGen, \"live_patch\", {url: href}, resp => {\n this.liveSocket.requestDOMUpdate(() => {\n if(resp.link_redirect){\n this.liveSocket.replaceMain(href, null, callback, linkRef)\n } else {\n if(this.liveSocket.commitPendingLink(linkRef)){\n this.href = href\n }\n this.applyPendingUpdates()\n callback && callback(linkRef)\n }\n })\n })\n\n if(push){\n push.receive(\"timeout\", fallback)\n } else {\n fallback()\n }\n }\n\n formsForRecovery(html){\n if(this.joinCount === 0){ return [] }\n\n let phxChange = this.binding(\"change\")\n let template = document.createElement(\"template\")\n template.innerHTML = html\n\n return (\n DOM.all(this.el, `form[${phxChange}]`)\n .filter(form => form.id && this.ownsElement(form))\n .filter(form => form.elements.length > 0)\n .filter(form => form.getAttribute(this.binding(PHX_AUTO_RECOVER)) !== \"ignore\")\n .map(form => {\n let newForm = template.content.querySelector(`form[id=\"${form.id}\"][${phxChange}=\"${form.getAttribute(phxChange)}\"]`)\n if(newForm){\n return [form, newForm, this.targetComponentID(newForm)]\n } else {\n return [form, null, null]\n }\n })\n .filter(([form, newForm, newCid]) => newForm)\n )\n }\n\n maybePushComponentsDestroyed(destroyedCIDs){\n let willDestroyCIDs = destroyedCIDs.filter(cid => {\n return DOM.findComponentNodeList(this.el, cid).length === 0\n })\n if(willDestroyCIDs.length > 0){\n this.pruningCIDs.push(...willDestroyCIDs)\n\n this.pushWithReply(null, \"cids_will_destroy\", {cids: willDestroyCIDs}, () => {\n // The cids are either back on the page or they will be fully removed,\n // so we can remove them from the pruningCIDs.\n this.pruningCIDs = this.pruningCIDs.filter(cid => willDestroyCIDs.indexOf(cid) !== -1)\n\n // See if any of the cids we wanted to destroy were added back,\n // if they were added back, we don't actually destroy them.\n let completelyDestroyCIDs = willDestroyCIDs.filter(cid => {\n return DOM.findComponentNodeList(this.el, cid).length === 0\n })\n\n if(completelyDestroyCIDs.length > 0){\n this.pushWithReply(null, \"cids_destroyed\", {cids: completelyDestroyCIDs}, (resp) => {\n this.rendered.pruneCIDs(resp.cids)\n })\n }\n })\n }\n }\n\n ownsElement(el){\n return el.getAttribute(PHX_PARENT_ID) === this.id ||\n maybe(el.closest(PHX_VIEW_SELECTOR), node => node.id) === this.id\n }\n\n submitForm(form, targetCtx, phxEvent, opts = {}){\n DOM.putPrivate(form, PHX_HAS_SUBMITTED, true)\n let phxFeedback = this.liveSocket.binding(PHX_FEEDBACK_FOR)\n let inputs = Array.from(form.elements)\n this.liveSocket.blurActiveElement(this)\n this.pushFormSubmit(form, targetCtx, phxEvent, opts, () => {\n inputs.forEach(input => DOM.showError(input, phxFeedback))\n this.liveSocket.restorePreviouslyActiveFocus()\n })\n }\n\n binding(kind){ return this.liveSocket.binding(kind) }\n}\n", "/** Initializes the LiveSocket\n *\n *\n * @param {string} endPoint - The string WebSocket endpoint, ie, `\"wss://example.com/live\"`,\n * `\"/live\"` (inherited host & protocol)\n * @param {Phoenix.Socket} socket - the required Phoenix Socket class imported from \"phoenix\". For example:\n *\n * import {Socket} from \"phoenix\"\n * import {LiveSocket} from \"phoenix_live_view\"\n * let liveSocket = new LiveSocket(\"/live\", Socket, {...})\n *\n * @param {Object} [opts] - Optional configuration. Outside of keys listed below, all\n * configuration is passed directly to the Phoenix Socket constructor.\n * @param {Object} [opts.defaults] - The optional defaults to use for various bindings,\n * such as `phx-debounce`. Supports the following keys:\n *\n * - debounce - the millisecond phx-debounce time. Defaults 300\n * - throttle - the millisecond phx-throttle time. Defaults 300\n *\n * @param {Function} [opts.params] - The optional function for passing connect params.\n * The function receives the element associated with a given LiveView. For example:\n *\n * (el) => {view: el.getAttribute(\"data-my-view-name\", token: window.myToken}\n *\n * @param {string} [opts.bindingPrefix] - The optional prefix to use for all phx DOM annotations.\n * Defaults to \"phx-\".\n * @param {Object} [opts.hooks] - The optional object for referencing LiveView hook callbacks.\n * @param {Object} [opts.uploaders] - The optional object for referencing LiveView uploader callbacks.\n * @param {integer} [opts.loaderTimeout] - The optional delay in milliseconds to wait before apply\n * loading states.\n * @param {integer} [opts.maxReloads] - The maximum reloads before entering failsafe mode.\n * @param {integer} [opts.reloadJitterMin] - The minimum time between normal reload attempts.\n * @param {integer} [opts.reloadJitterMax] - The maximum time between normal reload attempts.\n * @param {integer} [opts.failsafeJitter] - The time between reload attempts in failsafe mode.\n * @param {Function} [opts.viewLogger] - The optional function to log debug information. For example:\n *\n * (view, kind, msg, obj) => console.log(`${view.id} ${kind}: ${msg} - `, obj)\n *\n * @param {Object} [opts.metadata] - The optional object mapping event names to functions for\n * populating event metadata. For example:\n *\n * metadata: {\n * click: (e, el) => {\n * return {\n * ctrlKey: e.ctrlKey,\n * metaKey: e.metaKey,\n * detail: e.detail || 1,\n * }\n * },\n * keydown: (e, el) => {\n * return {\n * key: e.key,\n * ctrlKey: e.ctrlKey,\n * metaKey: e.metaKey,\n * shiftKey: e.shiftKey\n * }\n * }\n * }\n * @param {Object} [opts.sessionStorage] - An optional Storage compatible object\n * Useful when LiveView won't have access to `sessionStorage`. For example, This could\n * happen if a site loads a cross-domain LiveView in an iframe. Example usage:\n *\n * class InMemoryStorage {\n * constructor() { this.storage = {} }\n * getItem(keyName) { return this.storage[keyName] }\n * removeItem(keyName) { delete this.storage[keyName] }\n * setItem(keyName, keyValue) { this.storage[keyName] = keyValue }\n * }\n *\n * @param {Object} [opts.localStorage] - An optional Storage compatible object\n * Useful for when LiveView won't have access to `localStorage`.\n * See `opts.sessionStorage` for examples.\n*/\n\nimport {\n BINDING_PREFIX,\n CONSECUTIVE_RELOADS,\n DEFAULTS,\n FAILSAFE_JITTER,\n LOADER_TIMEOUT,\n MAX_RELOADS,\n PHX_DEBOUNCE,\n PHX_DROP_TARGET,\n PHX_HAS_FOCUSED,\n PHX_KEY,\n PHX_LINK_STATE,\n PHX_LIVE_LINK,\n PHX_LV_DEBUG,\n PHX_LV_LATENCY_SIM,\n PHX_LV_PROFILE,\n PHX_MAIN,\n PHX_PARENT_ID,\n PHX_VIEW_SELECTOR,\n PHX_ROOT_ID,\n PHX_THROTTLE,\n PHX_TRACK_UPLOADS,\n PHX_SESSION,\n RELOAD_JITTER_MIN,\n RELOAD_JITTER_MAX,\n} from \"./constants\"\n\nimport {\n clone,\n closestPhxBinding,\n closure,\n debug,\n isObject,\n maybe\n} from \"./utils\"\n\nimport Browser from \"./browser\"\nimport DOM from \"./dom\"\nimport Hooks from \"./hooks\"\nimport LiveUploader from \"./live_uploader\"\nimport View from \"./view\"\nimport JS from \"./js\"\n\nexport default class LiveSocket {\n constructor(url, phxSocket, opts = {}){\n this.unloaded = false\n if(!phxSocket || phxSocket.constructor.name === \"Object\"){\n throw new Error(`\n a phoenix Socket must be provided as the second argument to the LiveSocket constructor. For example:\n\n import {Socket} from \"phoenix\"\n import {LiveSocket} from \"phoenix_live_view\"\n let liveSocket = new LiveSocket(\"/live\", Socket, {...})\n `)\n }\n this.socket = new phxSocket(url, opts)\n this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX\n this.opts = opts\n this.params = closure(opts.params || {})\n this.viewLogger = opts.viewLogger\n this.metadataCallbacks = opts.metadata || {}\n this.defaults = Object.assign(clone(DEFAULTS), opts.defaults || {})\n this.activeElement = null\n this.prevActive = null\n this.silenced = false\n this.main = null\n this.outgoingMainEl = null\n this.clickStartedAtTarget = null\n this.linkRef = 1\n this.roots = {}\n this.href = window.location.href\n this.pendingLink = null\n this.currentLocation = clone(window.location)\n this.hooks = opts.hooks || {}\n this.uploaders = opts.uploaders || {}\n this.loaderTimeout = opts.loaderTimeout || LOADER_TIMEOUT\n this.reloadWithJitterTimer = null\n this.maxReloads = opts.maxReloads || MAX_RELOADS\n this.reloadJitterMin = opts.reloadJitterMin || RELOAD_JITTER_MIN\n this.reloadJitterMax = opts.reloadJitterMax || RELOAD_JITTER_MAX\n this.failsafeJitter = opts.failsafeJitter || FAILSAFE_JITTER\n this.localStorage = opts.localStorage || window.localStorage\n this.sessionStorage = opts.sessionStorage || window.sessionStorage\n this.boundTopLevelEvents = false\n this.domCallbacks = Object.assign({onNodeAdded: closure(), onBeforeElUpdated: closure()}, opts.dom || {})\n this.transitions = new TransitionSet()\n window.addEventListener(\"pagehide\", _e => {\n this.unloaded = true\n })\n this.socket.onOpen(() => {\n if(this.isUnloaded()){\n // reload page if being restored from back/forward cache and browser does not emit \"pageshow\"\n window.location.reload()\n }\n })\n }\n\n // public\n\n isProfileEnabled(){ return this.sessionStorage.getItem(PHX_LV_PROFILE) === \"true\" }\n\n isDebugEnabled(){ return this.sessionStorage.getItem(PHX_LV_DEBUG) === \"true\" }\n\n isDebugDisabled(){ return this.sessionStorage.getItem(PHX_LV_DEBUG) === \"false\" }\n\n enableDebug(){ this.sessionStorage.setItem(PHX_LV_DEBUG, \"true\") }\n\n enableProfiling(){ this.sessionStorage.setItem(PHX_LV_PROFILE, \"true\") }\n\n disableDebug(){ this.sessionStorage.setItem(PHX_LV_DEBUG, \"false\") }\n\n disableProfiling(){ this.sessionStorage.removeItem(PHX_LV_PROFILE) }\n\n enableLatencySim(upperBoundMs){\n this.enableDebug()\n console.log(\"latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable\")\n this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs)\n }\n\n disableLatencySim(){ this.sessionStorage.removeItem(PHX_LV_LATENCY_SIM) }\n\n getLatencySim(){\n let str = this.sessionStorage.getItem(PHX_LV_LATENCY_SIM)\n return str ? parseInt(str) : null\n }\n\n getSocket(){ return this.socket }\n\n connect(){\n // enable debug by default if on localhost and not explicitly disabled\n if(window.location.hostname === \"localhost\" && !this.isDebugDisabled()){ this.enableDebug() }\n let doConnect = () => {\n if(this.joinRootViews()){\n this.bindTopLevelEvents()\n this.socket.connect()\n } else if(this.main){\n this.socket.connect()\n }\n }\n if([\"complete\", \"loaded\", \"interactive\"].indexOf(document.readyState) >= 0){\n doConnect()\n } else {\n document.addEventListener(\"DOMContentLoaded\", () => doConnect())\n }\n }\n\n disconnect(callback){\n clearTimeout(this.reloadWithJitterTimer)\n this.socket.disconnect(callback)\n }\n\n replaceTransport(transport){\n clearTimeout(this.reloadWithJitterTimer)\n this.socket.replaceTransport(transport)\n this.connect()\n }\n\n execJS(el, encodedJS, eventType = null){\n this.owner(el, view => JS.exec(eventType, encodedJS, view, el))\n }\n\n // private\n\n triggerDOM(kind, args){ this.domCallbacks[kind](...args) }\n\n time(name, func){\n if(!this.isProfileEnabled() || !console.time){ return func() }\n console.time(name)\n let result = func()\n console.timeEnd(name)\n return result\n }\n\n log(view, kind, msgCallback){\n if(this.viewLogger){\n let [msg, obj] = msgCallback()\n this.viewLogger(view, kind, msg, obj)\n } else if(this.isDebugEnabled()){\n let [msg, obj] = msgCallback()\n debug(view, kind, msg, obj)\n }\n }\n\n requestDOMUpdate(callback){\n this.transitions.after(callback)\n }\n\n transition(time, onStart, onDone = function(){}){\n this.transitions.addTransition(time, onStart, onDone)\n }\n\n onChannel(channel, event, cb){\n channel.on(event, data => {\n let latency = this.getLatencySim()\n if(!latency){\n cb(data)\n } else {\n console.log(`simulating ${latency}ms of latency from server to client`)\n setTimeout(() => cb(data), latency)\n }\n })\n }\n\n wrapPush(view, opts, push){\n let latency = this.getLatencySim()\n let oldJoinCount = view.joinCount\n if(!latency){\n if(this.isConnected() && opts.timeout){\n return push().receive(\"timeout\", () => {\n if(view.joinCount === oldJoinCount && !view.isDestroyed()){\n this.reloadWithJitter(view, () => {\n this.log(view, \"timeout\", () => [\"received timeout while communicating with server. Falling back to hard refresh for recovery\"])\n })\n }\n })\n } else {\n return push()\n }\n }\n\n console.log(`simulating ${latency}ms of latency from client to server`)\n let fakePush = {\n receives: [],\n receive(kind, cb){ this.receives.push([kind, cb]) }\n }\n setTimeout(() => {\n if(view.isDestroyed()){ return }\n fakePush.receives.reduce((acc, [kind, cb]) => acc.receive(kind, cb), push())\n }, latency)\n return fakePush\n }\n\n reloadWithJitter(view, log){\n clearTimeout(this.reloadWithJitterTimer)\n this.disconnect()\n let minMs = this.reloadJitterMin\n let maxMs = this.reloadJitterMax\n let afterMs = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs\n let tries = Browser.updateLocal(this.localStorage, window.location.pathname, CONSECUTIVE_RELOADS, 0, count => count + 1)\n if(tries > this.maxReloads){\n afterMs = this.failsafeJitter\n }\n this.reloadWithJitterTimer = setTimeout(() => {\n // if view has recovered, such as transport replaced, then cancel\n if(view.isDestroyed() || view.isConnected()){ return }\n view.destroy()\n log ? log() : this.log(view, \"join\", () => [`encountered ${tries} consecutive reloads`])\n if(tries > this.maxReloads){\n this.log(view, \"join\", () => [`exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode`])\n }\n if(this.hasPendingLink()){\n window.location = this.pendingLink\n } else {\n window.location.reload()\n }\n }, afterMs)\n }\n\n getHookCallbacks(name){\n return name && name.startsWith(\"Phoenix.\") ? Hooks[name.split(\".\")[1]] : this.hooks[name]\n }\n\n isUnloaded(){ return this.unloaded }\n\n isConnected(){ return this.socket.isConnected() }\n\n getBindingPrefix(){ return this.bindingPrefix }\n\n binding(kind){ return `${this.getBindingPrefix()}${kind}` }\n\n channel(topic, params){ return this.socket.channel(topic, params) }\n\n joinRootViews(){\n let rootsFound = false\n DOM.all(document, `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, rootEl => {\n if(!this.getRootById(rootEl.id)){\n let view = this.newRootView(rootEl)\n view.setHref(this.getHref())\n view.join()\n if(rootEl.getAttribute(PHX_MAIN)){ this.main = view }\n }\n rootsFound = true\n })\n return rootsFound\n }\n\n redirect(to, flash){\n this.disconnect()\n Browser.redirect(to, flash)\n }\n\n replaceMain(href, flash, callback = null, linkRef = this.setPendingLink(href)){\n this.outgoingMainEl = this.outgoingMainEl || this.main.el\n let newMainEl = DOM.cloneNode(this.outgoingMainEl, \"\")\n this.main.showLoader(this.loaderTimeout)\n this.main.destroy()\n\n this.main = this.newRootView(newMainEl, flash)\n this.main.setRedirect(href)\n this.transitionRemoves()\n this.main.join((joinCount, onDone) => {\n if(joinCount === 1 && this.commitPendingLink(linkRef)){\n this.requestDOMUpdate(() => {\n DOM.findPhxSticky(document).forEach(el => newMainEl.appendChild(el))\n this.outgoingMainEl.replaceWith(newMainEl)\n this.outgoingMainEl = null\n callback && requestAnimationFrame(callback)\n onDone()\n })\n }\n })\n }\n\n transitionRemoves(elements){\n let removeAttr = this.binding(\"remove\")\n elements = elements || DOM.all(document, `[${removeAttr}]`)\n elements.forEach(el => {\n if(document.body.contains(el)){ // skip children already removed\n this.execJS(el, el.getAttribute(removeAttr), \"remove\")\n }\n })\n }\n\n isPhxView(el){ return el.getAttribute && el.getAttribute(PHX_SESSION) !== null }\n\n newRootView(el, flash){\n let view = new View(el, this, null, flash)\n this.roots[view.id] = view\n return view\n }\n\n owner(childEl, callback){\n let view = maybe(childEl.closest(PHX_VIEW_SELECTOR), el => this.getViewByEl(el)) || this.main\n if(view){ callback(view) }\n }\n\n withinOwners(childEl, callback){\n this.owner(childEl, view => callback(view, childEl))\n }\n\n getViewByEl(el){\n let rootId = el.getAttribute(PHX_ROOT_ID)\n return maybe(this.getRootById(rootId), root => root.getDescendentByEl(el))\n }\n\n getRootById(id){ return this.roots[id] }\n\n destroyAllViews(){\n for(let id in this.roots){\n this.roots[id].destroy()\n delete this.roots[id]\n }\n this.main = null\n }\n\n destroyViewByEl(el){\n let root = this.getRootById(el.getAttribute(PHX_ROOT_ID))\n if(root && root.id === el.id){\n root.destroy()\n delete this.roots[root.id]\n } else if(root){\n root.destroyDescendent(el.id)\n }\n }\n\n setActiveElement(target){\n if(this.activeElement === target){ return }\n this.activeElement = target\n let cancel = () => {\n if(target === this.activeElement){ this.activeElement = null }\n target.removeEventListener(\"mouseup\", this)\n target.removeEventListener(\"touchend\", this)\n }\n target.addEventListener(\"mouseup\", cancel)\n target.addEventListener(\"touchend\", cancel)\n }\n\n getActiveElement(){\n if(document.activeElement === document.body){\n return this.activeElement || document.activeElement\n } else {\n // document.activeElement can be null in Internet Explorer 11\n return document.activeElement || document.body\n }\n }\n\n dropActiveElement(view){\n if(this.prevActive && view.ownsElement(this.prevActive)){\n this.prevActive = null\n }\n }\n\n restorePreviouslyActiveFocus(){\n if(this.prevActive && this.prevActive !== document.body){\n this.prevActive.focus()\n }\n }\n\n blurActiveElement(){\n this.prevActive = this.getActiveElement()\n if(this.prevActive !== document.body){ this.prevActive.blur() }\n }\n\n bindTopLevelEvents(){\n if(this.boundTopLevelEvents){ return }\n\n this.boundTopLevelEvents = true\n // enter failsafe reload if server has gone away intentionally, such as \"disconnect\" broadcast\n this.socket.onClose(event => {\n if(event && event.code === 1000 && this.main){\n this.reloadWithJitter(this.main)\n }\n })\n document.body.addEventListener(\"click\", function (){ }) // ensure all click events bubble for mobile Safari\n window.addEventListener(\"pageshow\", e => {\n if(e.persisted){ // reload page if being restored from back/forward cache\n this.getSocket().disconnect()\n this.withPageLoading({to: window.location.href, kind: \"redirect\"})\n window.location.reload()\n }\n }, true)\n this.bindNav()\n this.bindClicks()\n this.bindForms()\n this.bind({keyup: \"keyup\", keydown: \"keydown\"}, (e, type, view, targetEl, phxEvent, eventTarget) => {\n let matchKey = targetEl.getAttribute(this.binding(PHX_KEY))\n let pressedKey = e.key && e.key.toLowerCase() // chrome clicked autocompletes send a keydown without key\n if(matchKey && matchKey.toLowerCase() !== pressedKey){ return }\n\n let data = {key: e.key, ...this.eventMeta(type, e, targetEl)}\n JS.exec(type, phxEvent, view, targetEl, [\"push\", {data}])\n })\n this.bind({blur: \"focusout\", focus: \"focusin\"}, (e, type, view, targetEl, phxEvent, eventTarget) => {\n if(!eventTarget){\n let data = {key: e.key, ...this.eventMeta(type, e, targetEl)}\n JS.exec(type, phxEvent, view, targetEl, [\"push\", {data}])\n }\n })\n this.bind({blur: \"blur\", focus: \"focus\"}, (e, type, view, targetEl, targetCtx, phxEvent, phxTarget) => {\n // blur and focus are triggered on document and window. Discard one to avoid dups\n if(phxTarget === \"window\"){\n let data = this.eventMeta(type, e, targetEl)\n JS.exec(type, phxEvent, view, targetEl, [\"push\", {data}])\n }\n })\n window.addEventListener(\"dragover\", e => e.preventDefault())\n window.addEventListener(\"drop\", e => {\n e.preventDefault()\n let dropTargetId = maybe(closestPhxBinding(e.target, this.binding(PHX_DROP_TARGET)), trueTarget => {\n return trueTarget.getAttribute(this.binding(PHX_DROP_TARGET))\n })\n let dropTarget = dropTargetId && document.getElementById(dropTargetId)\n let files = Array.from(e.dataTransfer.files || [])\n if(!dropTarget || dropTarget.disabled || files.length === 0 || !(dropTarget.files instanceof FileList)){ return }\n\n LiveUploader.trackFiles(dropTarget, files)\n dropTarget.dispatchEvent(new Event(\"input\", {bubbles: true}))\n })\n this.on(PHX_TRACK_UPLOADS, e => {\n let uploadTarget = e.target\n if(!DOM.isUploadInput(uploadTarget)){ return }\n let files = Array.from(e.detail.files || []).filter(f => f instanceof File || f instanceof Blob)\n LiveUploader.trackFiles(uploadTarget, files)\n uploadTarget.dispatchEvent(new Event(\"input\", {bubbles: true}))\n })\n }\n\n eventMeta(eventName, e, targetEl){\n let callback = this.metadataCallbacks[eventName]\n return callback ? callback(e, targetEl) : {}\n }\n\n setPendingLink(href){\n this.linkRef++\n this.pendingLink = href\n return this.linkRef\n }\n\n commitPendingLink(linkRef){\n if(this.linkRef !== linkRef){\n return false\n } else {\n this.href = this.pendingLink\n this.pendingLink = null\n return true\n }\n }\n\n getHref(){ return this.href }\n\n hasPendingLink(){ return !!this.pendingLink }\n\n bind(events, callback){\n for(let event in events){\n let browserEventName = events[event]\n\n this.on(browserEventName, e => {\n let binding = this.binding(event)\n let windowBinding = this.binding(`window-${event}`)\n let targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding)\n if(targetPhxEvent){\n this.debounce(e.target, e, browserEventName, () => {\n this.withinOwners(e.target, view => {\n callback(e, event, view, e.target, targetPhxEvent, null)\n })\n })\n } else {\n DOM.all(document, `[${windowBinding}]`, el => {\n let phxEvent = el.getAttribute(windowBinding)\n this.debounce(el, e, browserEventName, () => {\n this.withinOwners(el, view => {\n callback(e, event, view, el, phxEvent, \"window\")\n })\n })\n })\n }\n })\n }\n }\n\n bindClicks(){\n window.addEventListener(\"mousedown\", e => this.clickStartedAtTarget = e.target)\n this.bindClick(\"click\", \"click\", false)\n this.bindClick(\"mousedown\", \"capture-click\", true)\n }\n\n bindClick(eventName, bindingName, capture){\n let click = this.binding(bindingName)\n window.addEventListener(eventName, e => {\n let target = null\n if(capture){\n target = e.target.matches(`[${click}]`) ? e.target : e.target.querySelector(`[${click}]`)\n } else {\n let clickStartedAtTarget = this.clickStartedAtTarget || e.target\n target = closestPhxBinding(clickStartedAtTarget, click)\n this.dispatchClickAway(e, clickStartedAtTarget)\n this.clickStartedAtTarget = null\n }\n let phxEvent = target && target.getAttribute(click)\n if(!phxEvent){ return }\n if(target.getAttribute(\"href\") === \"#\"){ e.preventDefault() }\n\n this.debounce(target, e, \"click\", () => {\n this.withinOwners(target, view => {\n JS.exec(\"click\", phxEvent, view, target, [\"push\", {data: this.eventMeta(\"click\", e, target)}])\n })\n })\n }, capture)\n }\n\n dispatchClickAway(e, clickStartedAt){\n let phxClickAway = this.binding(\"click-away\")\n DOM.all(document, `[${phxClickAway}]`, el => {\n if(!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))){\n this.withinOwners(e.target, view => {\n let phxEvent = el.getAttribute(phxClickAway)\n if(JS.isVisible(el)){\n JS.exec(\"click\", phxEvent, view, el, [\"push\", {data: this.eventMeta(\"click\", e, e.target)}])\n }\n })\n }\n })\n }\n\n bindNav(){\n if(!Browser.canPushState()){ return }\n if(history.scrollRestoration){ history.scrollRestoration = \"manual\" }\n let scrollTimer = null\n window.addEventListener(\"scroll\", _e => {\n clearTimeout(scrollTimer)\n scrollTimer = setTimeout(() => {\n Browser.updateCurrentState(state => Object.assign(state, {scroll: window.scrollY}))\n }, 100)\n })\n window.addEventListener(\"popstate\", event => {\n if(!this.registerNewLocation(window.location)){ return }\n let {type, id, root, scroll} = event.state || {}\n let href = window.location.href\n\n this.requestDOMUpdate(() => {\n if(this.main.isConnected() && (type === \"patch\" && id === this.main.id)){\n this.main.pushLinkPatch(href, null)\n } else {\n this.replaceMain(href, null, () => {\n if(root){ this.replaceRootHistory() }\n if(typeof(scroll) === \"number\"){\n setTimeout(() => {\n window.scrollTo(0, scroll)\n }, 0) // the body needs to render before we scroll.\n }\n })\n }\n })\n }, false)\n window.addEventListener(\"click\", e => {\n let target = closestPhxBinding(e.target, PHX_LIVE_LINK)\n let type = target && target.getAttribute(PHX_LIVE_LINK)\n let wantsNewTab = e.metaKey || e.ctrlKey || e.button === 1\n if(!type || !this.isConnected() || !this.main || wantsNewTab){ return }\n\n let href = target.href\n let linkState = target.getAttribute(PHX_LINK_STATE)\n e.preventDefault()\n e.stopImmediatePropagation() // do not bubble click to regular phx-click bindings\n if(this.pendingLink === href){ return }\n\n this.requestDOMUpdate(() => {\n if(type === \"patch\"){\n this.pushHistoryPatch(href, linkState, target)\n } else if(type === \"redirect\"){\n this.historyRedirect(href, linkState)\n } else {\n throw new Error(`expected ${PHX_LIVE_LINK} to be \"patch\" or \"redirect\", got: ${type}`)\n }\n })\n }, false)\n }\n\n dispatchEvent(event, payload = {}){\n DOM.dispatchEvent(window, `phx:${event}`, {detail: payload})\n }\n\n dispatchEvents(events){\n events.forEach(([event, payload]) => this.dispatchEvent(event, payload))\n }\n\n withPageLoading(info, callback){\n DOM.dispatchEvent(window, \"phx:page-loading-start\", {detail: info})\n let done = () => DOM.dispatchEvent(window, \"phx:page-loading-stop\", {detail: info})\n return callback ? callback(done) : done\n }\n\n pushHistoryPatch(href, linkState, targetEl){\n this.withPageLoading({to: href, kind: \"patch\"}, done => {\n this.main.pushLinkPatch(href, targetEl, linkRef => {\n this.historyPatch(href, linkState, linkRef)\n done()\n })\n })\n }\n\n historyPatch(href, linkState, linkRef = this.setPendingLink(href)){\n if(!this.commitPendingLink(linkRef)){ return }\n\n Browser.pushState(linkState, {type: \"patch\", id: this.main.id}, href)\n this.registerNewLocation(window.location)\n }\n\n historyRedirect(href, linkState, flash){\n let scroll = window.scrollY\n this.withPageLoading({to: href, kind: \"redirect\"}, done => {\n this.replaceMain(href, flash, () => {\n Browser.pushState(linkState, {type: \"redirect\", id: this.main.id, scroll: scroll}, href)\n this.registerNewLocation(window.location)\n done()\n })\n })\n }\n\n replaceRootHistory(){\n Browser.pushState(\"replace\", {root: true, type: \"patch\", id: this.main.id})\n }\n\n registerNewLocation(newLocation){\n let {pathname, search} = this.currentLocation\n if(pathname + search === newLocation.pathname + newLocation.search){\n return false\n } else {\n this.currentLocation = clone(newLocation)\n return true\n }\n }\n\n bindForms(){\n let iterations = 0\n this.on(\"submit\", e => {\n let phxEvent = e.target.getAttribute(this.binding(\"submit\"))\n if(!phxEvent){ return }\n e.preventDefault()\n e.target.disabled = true\n this.withinOwners(e.target, view => {\n JS.exec(\"submit\", phxEvent, view, e.target, [\"push\", {}])\n })\n }, false)\n\n for(let type of [\"change\", \"input\"]){\n this.on(type, e => {\n let phxChange = this.binding(\"change\")\n let input = e.target\n let inputEvent = input.getAttribute(phxChange)\n let formEvent = input.form && input.form.getAttribute(phxChange)\n let phxEvent = inputEvent || formEvent\n if(!phxEvent){ return }\n if(input.type === \"number\" && input.validity && input.validity.badInput){ return }\n\n let dispatcher = inputEvent ? input : input.form\n let currentIterations = iterations\n iterations++\n let {at: at, type: lastType} = DOM.private(input, \"prev-iteration\") || {}\n // detect dup because some browsers dispatch both \"input\" and \"change\"\n if(at === currentIterations - 1 && type !== lastType){ return }\n\n DOM.putPrivate(input, \"prev-iteration\", {at: currentIterations, type: type})\n\n this.debounce(input, e, type, () => {\n this.withinOwners(dispatcher, view => {\n DOM.putPrivate(input, PHX_HAS_FOCUSED, true)\n if(!DOM.isTextualInput(input)){\n this.setActiveElement(input)\n }\n JS.exec(\"change\", phxEvent, view, input, [\"push\", {_target: e.target.name, dispatcher: dispatcher}])\n })\n })\n }, false)\n }\n }\n\n debounce(el, event, eventType, callback){\n if(eventType === \"blur\" || eventType === \"focusout\"){ return callback() }\n\n let phxDebounce = this.binding(PHX_DEBOUNCE)\n let phxThrottle = this.binding(PHX_THROTTLE)\n let defaultDebounce = this.defaults.debounce.toString()\n let defaultThrottle = this.defaults.throttle.toString()\n\n this.withinOwners(el, view => {\n let asyncFilter = () => !view.isDestroyed() && document.body.contains(el)\n DOM.debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, () => {\n callback()\n })\n })\n }\n\n silenceEvents(callback){\n this.silenced = true\n callback()\n this.silenced = false\n }\n\n on(event, callback){\n window.addEventListener(event, e => {\n if(!this.silenced){ callback(e) }\n })\n }\n}\n\nclass TransitionSet {\n constructor(){\n this.transitions = new Set()\n this.pendingOps = []\n this.reset()\n }\n\n reset(){\n this.transitions.forEach(timer => {\n cancelTimeout(timer)\n this.transitions.delete(timer)\n })\n this.flushPendingOps()\n }\n\n after(callback){\n if(this.size() === 0){\n callback()\n } else {\n this.pushPendingOp(callback)\n }\n }\n\n addTransition(time, onStart, onDone){\n onStart()\n let timer = setTimeout(() => {\n this.transitions.delete(timer)\n onDone()\n if(this.size() === 0){ this.flushPendingOps() }\n }, time)\n this.transitions.add(timer)\n }\n\n pushPendingOp(op){ this.pendingOps.push(op) }\n\n size(){ return this.transitions.size }\n\n flushPendingOps(){\n this.pendingOps.forEach(op => op())\n this.pendingOps = []\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["/*\n================================================================================\nPhoenix LiveView JavaScript Client\n================================================================================\n\nSee the hexdocs at `https://hexdocs.pm/phoenix_live_view` for documentation.\n\n*/\n\nimport LiveSocket from \"./live_socket\"\nexport {\n LiveSocket\n}\n", "\nexport const CONSECUTIVE_RELOADS = \"consecutive-reloads\"\nexport const MAX_RELOADS = 10\nexport const RELOAD_JITTER_MIN = 5000\nexport const RELOAD_JITTER_MAX = 10000\nexport const FAILSAFE_JITTER = 30000\nexport const PHX_EVENT_CLASSES = [\n \"phx-click-loading\", \"phx-change-loading\", \"phx-submit-loading\",\n \"phx-keydown-loading\", \"phx-keyup-loading\", \"phx-blur-loading\", \"phx-focus-loading\"\n]\nexport const PHX_COMPONENT = \"data-phx-component\"\nexport const PHX_LIVE_LINK = \"data-phx-link\"\nexport const PHX_TRACK_STATIC = \"track-static\"\nexport const PHX_LINK_STATE = \"data-phx-link-state\"\nexport const PHX_REF = \"data-phx-ref\"\nexport const PHX_REF_SRC = \"data-phx-ref-src\"\nexport const PHX_TRACK_UPLOADS = \"track-uploads\"\nexport const PHX_UPLOAD_REF = \"data-phx-upload-ref\"\nexport const PHX_PREFLIGHTED_REFS = \"data-phx-preflighted-refs\"\nexport const PHX_DONE_REFS = \"data-phx-done-refs\"\nexport const PHX_DROP_TARGET = \"drop-target\"\nexport const PHX_ACTIVE_ENTRY_REFS = \"data-phx-active-refs\"\nexport const PHX_LIVE_FILE_UPDATED = \"phx:live-file:updated\"\nexport const PHX_SKIP = \"data-phx-skip\"\nexport const PHX_PRUNE = \"data-phx-prune\"\nexport const PHX_PAGE_LOADING = \"page-loading\"\nexport const PHX_CONNECTED_CLASS = \"phx-connected\"\nexport const PHX_DISCONNECTED_CLASS = \"phx-loading\"\nexport const PHX_NO_FEEDBACK_CLASS = \"phx-no-feedback\"\nexport const PHX_ERROR_CLASS = \"phx-error\"\nexport const PHX_PARENT_ID = \"data-phx-parent-id\"\nexport const PHX_MAIN = \"data-phx-main\"\nexport const PHX_ROOT_ID = \"data-phx-root-id\"\nexport const PHX_TRIGGER_ACTION = \"trigger-action\"\nexport const PHX_FEEDBACK_FOR = \"feedback-for\"\nexport const PHX_HAS_FOCUSED = \"phx-has-focused\"\nexport const FOCUSABLE_INPUTS = [\"text\", \"textarea\", \"number\", \"email\", \"password\", \"search\", \"tel\", \"url\", \"date\", \"time\", \"datetime-local\", \"color\", \"range\"]\nexport const CHECKABLE_INPUTS = [\"checkbox\", \"radio\"]\nexport const PHX_HAS_SUBMITTED = \"phx-has-submitted\"\nexport const PHX_SESSION = \"data-phx-session\"\nexport const PHX_VIEW_SELECTOR = `[${PHX_SESSION}]`\nexport const PHX_STICKY = \"data-phx-sticky\"\nexport const PHX_STATIC = \"data-phx-static\"\nexport const PHX_READONLY = \"data-phx-readonly\"\nexport const PHX_DISABLED = \"data-phx-disabled\"\nexport const PHX_DISABLE_WITH = \"disable-with\"\nexport const PHX_DISABLE_WITH_RESTORE = \"data-phx-disable-with-restore\"\nexport const PHX_HOOK = \"hook\"\nexport const PHX_DEBOUNCE = \"debounce\"\nexport const PHX_THROTTLE = \"throttle\"\nexport const PHX_UPDATE = \"update\"\nexport const PHX_KEY = \"key\"\nexport const PHX_PRIVATE = \"phxPrivate\"\nexport const PHX_AUTO_RECOVER = \"auto-recover\"\nexport const PHX_LV_DEBUG = \"phx:live-socket:debug\"\nexport const PHX_LV_PROFILE = \"phx:live-socket:profiling\"\nexport const PHX_LV_LATENCY_SIM = \"phx:live-socket:latency-sim\"\nexport const PHX_PROGRESS = \"progress\"\nexport const LOADER_TIMEOUT = 1\nexport const BEFORE_UNLOAD_LOADER_TIMEOUT = 200\nexport const BINDING_PREFIX = \"phx-\"\nexport const PUSH_TIMEOUT = 30000\nexport const LINK_HEADER = \"x-requested-with\"\nexport const RESPONSE_URL_HEADER = \"x-response-url\"\nexport const DEBOUNCE_TRIGGER = \"debounce-trigger\"\nexport const THROTTLED = \"throttled\"\nexport const DEBOUNCE_PREV_KEY = \"debounce-prev-key\"\nexport const DEFAULTS = {\n debounce: 300,\n throttle: 300\n}\n\n// Rendered\nexport const DYNAMICS = \"d\"\nexport const STATIC = \"s\"\nexport const COMPONENTS = \"c\"\nexport const EVENTS = \"e\"\nexport const REPLY = \"r\"\nexport const TITLE = \"t\"\nexport const TEMPLATES = \"p\"\n", "import {\n logError\n} from \"./utils\"\n\nexport default class EntryUploader {\n constructor(entry, chunkSize, liveSocket){\n this.liveSocket = liveSocket\n this.entry = entry\n this.offset = 0\n this.chunkSize = chunkSize\n this.chunkTimer = null\n this.uploadChannel = liveSocket.channel(`lvu:${entry.ref}`, {token: entry.metadata()})\n }\n\n error(reason){\n clearTimeout(this.chunkTimer)\n this.uploadChannel.leave()\n this.entry.error(reason)\n }\n\n upload(){\n this.uploadChannel.onError(reason => this.error(reason))\n this.uploadChannel.join()\n .receive(\"ok\", _data => this.readNextChunk())\n .receive(\"error\", reason => this.error(reason))\n }\n\n isDone(){ return this.offset >= this.entry.file.size }\n\n readNextChunk(){\n let reader = new window.FileReader()\n let blob = this.entry.file.slice(this.offset, this.chunkSize + this.offset)\n reader.onload = (e) => {\n if(e.target.error === null){\n this.offset += e.target.result.byteLength\n this.pushChunk(e.target.result)\n } else {\n return logError(\"Read error: \" + e.target.error)\n }\n }\n reader.readAsArrayBuffer(blob)\n }\n\n pushChunk(chunk){\n if(!this.uploadChannel.isJoined()){ return }\n this.uploadChannel.push(\"chunk\", chunk)\n .receive(\"ok\", () => {\n this.entry.progress((this.offset / this.entry.file.size) * 100)\n if(!this.isDone()){\n this.chunkTimer = setTimeout(() => this.readNextChunk(), this.liveSocket.getLatencySim() || 0)\n }\n })\n }\n}\n", "import {\n PHX_VIEW_SELECTOR\n} from \"./constants\"\n\nimport EntryUploader from \"./entry_uploader\"\n\nexport let logError = (msg, obj) => console.error && console.error(msg, obj)\n\nexport let isCid = (cid) => {\n let type = typeof(cid)\n return type === \"number\" || (type === \"string\" && /^(0|[1-9]\\d*)$/.test(cid))\n}\n\nexport function detectDuplicateIds(){\n let ids = new Set()\n let elems = document.querySelectorAll(\"*[id]\")\n for(let i = 0, len = elems.length; i < len; i++){\n if(ids.has(elems[i].id)){\n console.error(`Multiple IDs detected: ${elems[i].id}. Ensure unique element ids.`)\n } else {\n ids.add(elems[i].id)\n }\n }\n}\n\nexport let debug = (view, kind, msg, obj) => {\n if(view.liveSocket.isDebugEnabled()){\n console.log(`${view.id} ${kind}: ${msg} - `, obj)\n }\n}\n\n// wraps value in closure or returns closure\nexport let closure = (val) => typeof val === \"function\" ? val : function (){ return val }\n\nexport let clone = (obj) => { return JSON.parse(JSON.stringify(obj)) }\n\nexport let closestPhxBinding = (el, binding, borderEl) => {\n do {\n if(el.matches(`[${binding}]`)){ return el }\n el = el.parentElement || el.parentNode\n } while(el !== null && el.nodeType === 1 && !((borderEl && borderEl.isSameNode(el)) || el.matches(PHX_VIEW_SELECTOR)))\n return null\n}\n\nexport let isObject = (obj) => {\n return obj !== null && typeof obj === \"object\" && !(obj instanceof Array)\n}\n\nexport let isEqualObj = (obj1, obj2) => JSON.stringify(obj1) === JSON.stringify(obj2)\n\nexport let isEmpty = (obj) => {\n for(let x in obj){ return false }\n return true\n}\n\nexport let maybe = (el, callback) => el && callback(el)\n\nexport let channelUploader = function (entries, onError, resp, liveSocket){\n entries.forEach(entry => {\n let entryUploader = new EntryUploader(entry, resp.config.chunk_size, liveSocket)\n entryUploader.upload()\n })\n}\n", "let Browser = {\n canPushState(){ return (typeof (history.pushState) !== \"undefined\") },\n\n dropLocal(localStorage, namespace, subkey){\n return localStorage.removeItem(this.localKey(namespace, subkey))\n },\n\n updateLocal(localStorage, namespace, subkey, initial, func){\n let current = this.getLocal(localStorage, namespace, subkey)\n let key = this.localKey(namespace, subkey)\n let newVal = current === null ? initial : func(current)\n localStorage.setItem(key, JSON.stringify(newVal))\n return newVal\n },\n\n getLocal(localStorage, namespace, subkey){\n return JSON.parse(localStorage.getItem(this.localKey(namespace, subkey)))\n },\n\n updateCurrentState(callback){\n if(!this.canPushState()){ return }\n history.replaceState(callback(history.state || {}), \"\", window.location.href)\n },\n\n pushState(kind, meta, to){\n if(this.canPushState()){\n if(to !== window.location.href){\n if(meta.type == \"redirect\" && meta.scroll){\n // If we're redirecting store the current scrollY for the current history state.\n let currentState = history.state || {}\n currentState.scroll = meta.scroll\n history.replaceState(currentState, \"\", window.location.href)\n }\n\n delete meta.scroll // Only store the scroll in the redirect case.\n history[kind + \"State\"](meta, \"\", to || null) // IE will coerce undefined to string\n let hashEl = this.getHashTargetEl(window.location.hash)\n\n if(hashEl){\n hashEl.scrollIntoView()\n } else if(meta.type === \"redirect\"){\n window.scroll(0, 0)\n }\n }\n } else {\n this.redirect(to)\n }\n },\n\n setCookie(name, value){\n document.cookie = `${name}=${value}`\n },\n\n getCookie(name){\n return document.cookie.replace(new RegExp(`(?:(?:^|.*;\\s*)${name}\\s*\\=\\s*([^;]*).*$)|^.*$`), \"$1\")\n },\n\n redirect(toURL, flash){\n if(flash){ Browser.setCookie(\"__phoenix_flash__\", flash + \"; max-age=60000; path=/\") }\n window.location = toURL\n },\n\n localKey(namespace, subkey){ return `${namespace}-${subkey}` },\n\n getHashTargetEl(maybeHash){\n let hash = maybeHash.toString().substring(1)\n if(hash === \"\"){ return }\n return document.getElementById(hash) || document.querySelector(`a[name=\"${hash}\"]`)\n }\n}\n\nexport default Browser\n", "import {\n CHECKABLE_INPUTS,\n DEBOUNCE_PREV_KEY,\n DEBOUNCE_TRIGGER,\n FOCUSABLE_INPUTS,\n PHX_COMPONENT,\n PHX_EVENT_CLASSES,\n PHX_HAS_FOCUSED,\n PHX_HAS_SUBMITTED,\n PHX_MAIN,\n PHX_NO_FEEDBACK_CLASS,\n PHX_PARENT_ID,\n PHX_PRIVATE,\n PHX_REF,\n PHX_REF_SRC,\n PHX_ROOT_ID,\n PHX_SESSION,\n PHX_STATIC,\n PHX_UPLOAD_REF,\n PHX_VIEW_SELECTOR,\n PHX_STICKY,\n THROTTLED\n} from \"./constants\"\n\nimport {\n logError\n} from \"./utils\"\n\nlet DOM = {\n byId(id){ return document.getElementById(id) || logError(`no id found for ${id}`) },\n\n removeClass(el, className){\n el.classList.remove(className)\n if(el.classList.length === 0){ el.removeAttribute(\"class\") }\n },\n\n all(node, query, callback){\n if(!node){ return [] }\n let array = Array.from(node.querySelectorAll(query))\n return callback ? array.forEach(callback) : array\n },\n\n childNodeLength(html){\n let template = document.createElement(\"template\")\n template.innerHTML = html\n return template.content.childElementCount\n },\n\n isUploadInput(el){ return el.type === \"file\" && el.getAttribute(PHX_UPLOAD_REF) !== null },\n\n findUploadInputs(node){ return this.all(node, `input[type=\"file\"][${PHX_UPLOAD_REF}]`) },\n\n findComponentNodeList(node, cid){\n return this.filterWithinSameLiveView(this.all(node, `[${PHX_COMPONENT}=\"${cid}\"]`), node)\n },\n\n isPhxDestroyed(node){\n return node.id && DOM.private(node, \"destroyed\") ? true : false\n },\n\n markPhxChildDestroyed(el){\n if(this.isPhxChild(el)){ el.setAttribute(PHX_SESSION, \"\") }\n this.putPrivate(el, \"destroyed\", true)\n },\n\n findPhxChildrenInFragment(html, parentId){\n let template = document.createElement(\"template\")\n template.innerHTML = html\n return this.findPhxChildren(template.content, parentId)\n },\n\n isIgnored(el, phxUpdate){\n return (el.getAttribute(phxUpdate) || el.getAttribute(\"data-phx-update\")) === \"ignore\"\n },\n\n isPhxUpdate(el, phxUpdate, updateTypes){\n return el.getAttribute && updateTypes.indexOf(el.getAttribute(phxUpdate)) >= 0\n },\n\n findPhxSticky(el){ return this.all(el, `[${PHX_STICKY}]`) },\n\n findPhxChildren(el, parentId){\n return this.all(el, `${PHX_VIEW_SELECTOR}[${PHX_PARENT_ID}=\"${parentId}\"]`)\n },\n\n findParentCIDs(node, cids){\n let initial = new Set(cids)\n return cids.reduce((acc, cid) => {\n let selector = `[${PHX_COMPONENT}=\"${cid}\"] [${PHX_COMPONENT}]`\n\n this.filterWithinSameLiveView(this.all(node, selector), node)\n .map(el => parseInt(el.getAttribute(PHX_COMPONENT)))\n .forEach(childCID => acc.delete(childCID))\n\n return acc\n }, initial)\n },\n\n filterWithinSameLiveView(nodes, parent){\n if(parent.querySelector(PHX_VIEW_SELECTOR)){\n return nodes.filter(el => this.withinSameLiveView(el, parent))\n } else {\n return nodes\n }\n },\n\n withinSameLiveView(node, parent){\n while(node = node.parentNode){\n if(node.isSameNode(parent)){ return true }\n if(node.getAttribute(PHX_SESSION) !== null){ return false }\n }\n },\n\n private(el, key){ return el[PHX_PRIVATE] && el[PHX_PRIVATE][key] },\n\n deletePrivate(el, key){ el[PHX_PRIVATE] && delete (el[PHX_PRIVATE][key]) },\n\n putPrivate(el, key, value){\n if(!el[PHX_PRIVATE]){ el[PHX_PRIVATE] = {} }\n el[PHX_PRIVATE][key] = value\n },\n\n updatePrivate(el, key, defaultVal, updateFunc){\n let existing = this.private(el, key)\n if(existing === undefined){\n this.putPrivate(el, key, updateFunc(defaultVal))\n } else {\n this.putPrivate(el, key, updateFunc(existing))\n }\n },\n\n copyPrivates(target, source){\n if(source[PHX_PRIVATE]){\n target[PHX_PRIVATE] = source[PHX_PRIVATE]\n }\n },\n\n putTitle(str){\n let titleEl = document.querySelector(\"title\")\n let {prefix, suffix} = titleEl.dataset\n document.title = `${prefix || \"\"}${str}${suffix || \"\"}`\n },\n\n debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, callback){\n let debounce = el.getAttribute(phxDebounce)\n let throttle = el.getAttribute(phxThrottle)\n if(debounce === \"\"){ debounce = defaultDebounce }\n if(throttle === \"\"){ throttle = defaultThrottle }\n let value = debounce || throttle\n switch(value){\n case null: return callback()\n\n case \"blur\":\n if(this.once(el, \"debounce-blur\")){\n el.addEventListener(\"blur\", () => callback())\n }\n return\n\n default:\n let timeout = parseInt(value)\n let trigger = () => throttle ? this.deletePrivate(el, THROTTLED) : callback()\n let currentCycle = this.incCycle(el, DEBOUNCE_TRIGGER, trigger)\n if(isNaN(timeout)){ return logError(`invalid throttle/debounce value: ${value}`) }\n if(throttle){\n let newKeyDown = false\n if(event.type === \"keydown\"){\n let prevKey = this.private(el, DEBOUNCE_PREV_KEY)\n this.putPrivate(el, DEBOUNCE_PREV_KEY, event.key)\n newKeyDown = prevKey !== event.key\n }\n\n if(!newKeyDown && this.private(el, THROTTLED)){\n return false\n } else {\n callback()\n this.putPrivate(el, THROTTLED, true)\n setTimeout(() => {\n if(asyncFilter()){ this.triggerCycle(el, DEBOUNCE_TRIGGER) }\n }, timeout)\n }\n } else {\n setTimeout(() => {\n if(asyncFilter()){ this.triggerCycle(el, DEBOUNCE_TRIGGER, currentCycle) }\n }, timeout)\n }\n\n let form = el.form\n if(form && this.once(form, \"bind-debounce\")){\n form.addEventListener(\"submit\", () => {\n Array.from((new FormData(form)).entries(), ([name]) => {\n let input = form.querySelector(`[name=\"${name}\"]`)\n this.incCycle(input, DEBOUNCE_TRIGGER)\n this.deletePrivate(input, THROTTLED)\n })\n })\n }\n if(this.once(el, \"bind-debounce\")){\n el.addEventListener(\"blur\", () => this.triggerCycle(el, DEBOUNCE_TRIGGER))\n }\n }\n },\n\n triggerCycle(el, key, currentCycle){\n let [cycle, trigger] = this.private(el, key)\n if(!currentCycle){ currentCycle = cycle }\n if(currentCycle === cycle){\n this.incCycle(el, key)\n trigger()\n }\n },\n\n once(el, key){\n if(this.private(el, key) === true){ return false }\n this.putPrivate(el, key, true)\n return true\n },\n\n incCycle(el, key, trigger = function (){ }){\n let [currentCycle] = this.private(el, key) || [0, trigger]\n currentCycle++\n this.putPrivate(el, key, [currentCycle, trigger])\n return currentCycle\n },\n\n discardError(container, el, phxFeedbackFor){\n let field = el.getAttribute && el.getAttribute(phxFeedbackFor)\n // TODO: Remove id lookup after we update Phoenix to use input_name instead of input_id\n let input = field && container.querySelector(`[id=\"${field}\"], [name=\"${field}\"]`)\n if(!input){ return }\n\n if(!(this.private(input, PHX_HAS_FOCUSED) || this.private(input.form, PHX_HAS_SUBMITTED))){\n el.classList.add(PHX_NO_FEEDBACK_CLASS)\n }\n },\n\n showError(inputEl, phxFeedbackFor){\n if(inputEl.id || inputEl.name){\n this.all(inputEl.form, `[${phxFeedbackFor}=\"${inputEl.id}\"], [${phxFeedbackFor}=\"${inputEl.name}\"]`, (el) => {\n this.removeClass(el, PHX_NO_FEEDBACK_CLASS)\n })\n }\n },\n\n isPhxChild(node){\n return node.getAttribute && node.getAttribute(PHX_PARENT_ID)\n },\n\n isPhxSticky(node){\n return node.getAttribute && node.getAttribute(PHX_STICKY) !== null\n },\n\n firstPhxChild(el){\n return this.isPhxChild(el) ? el : this.all(el, `[${PHX_PARENT_ID}]`)[0]\n },\n\n dispatchEvent(target, name, opts = {}){\n let bubbles = opts.bubbles === undefined ? true : !!opts.bubbles\n let eventOpts = {bubbles: bubbles, cancelable: true, detail: opts.detail || {}}\n let event = name === \"click\" ? new MouseEvent(\"click\", eventOpts) : new CustomEvent(name, eventOpts)\n target.dispatchEvent(event)\n },\n\n cloneNode(node, html){\n if(typeof (html) === \"undefined\"){\n return node.cloneNode(true)\n } else {\n let cloned = node.cloneNode(false)\n cloned.innerHTML = html\n return cloned\n }\n },\n\n mergeAttrs(target, source, opts = {}){\n let exclude = opts.exclude || []\n let isIgnored = opts.isIgnored\n let sourceAttrs = source.attributes\n for(let i = sourceAttrs.length - 1; i >= 0; i--){\n let name = sourceAttrs[i].name\n if(exclude.indexOf(name) < 0){ target.setAttribute(name, source.getAttribute(name)) }\n }\n\n let targetAttrs = target.attributes\n for(let i = targetAttrs.length - 1; i >= 0; i--){\n let name = targetAttrs[i].name\n if(isIgnored){\n if(name.startsWith(\"data-\") && !source.hasAttribute(name)){ target.removeAttribute(name) }\n } else {\n if(!source.hasAttribute(name)){ target.removeAttribute(name) }\n }\n }\n },\n\n mergeFocusedInput(target, source){\n // skip selects because FF will reset highlighted index for any setAttribute\n if(!(target instanceof HTMLSelectElement)){ DOM.mergeAttrs(target, source, {exclude: [\"value\"]}) }\n if(source.readOnly){\n target.setAttribute(\"readonly\", true)\n } else {\n target.removeAttribute(\"readonly\")\n }\n },\n\n hasSelectionRange(el){\n return el.setSelectionRange && (el.type === \"text\" || el.type === \"textarea\")\n },\n\n restoreFocus(focused, selectionStart, selectionEnd){\n if(!DOM.isTextualInput(focused)){ return }\n let wasFocused = focused.matches(\":focus\")\n if(focused.readOnly){ focused.blur() }\n if(!wasFocused){ focused.focus() }\n if(this.hasSelectionRange(focused)){\n focused.setSelectionRange(selectionStart, selectionEnd)\n }\n },\n\n isFormInput(el){ return /^(?:input|select|textarea)$/i.test(el.tagName) && el.type !== \"button\" },\n\n syncAttrsToProps(el){\n if(el instanceof HTMLInputElement && CHECKABLE_INPUTS.indexOf(el.type.toLocaleLowerCase()) >= 0){\n el.checked = el.getAttribute(\"checked\") !== null\n }\n },\n\n isTextualInput(el){ return FOCUSABLE_INPUTS.indexOf(el.type) >= 0 },\n\n isNowTriggerFormExternal(el, phxTriggerExternal){\n return el.getAttribute && el.getAttribute(phxTriggerExternal) !== null\n },\n\n syncPendingRef(fromEl, toEl, disableWith){\n let ref = fromEl.getAttribute(PHX_REF)\n if(ref === null){ return true }\n let refSrc = fromEl.getAttribute(PHX_REF_SRC)\n\n if(DOM.isFormInput(fromEl) || fromEl.getAttribute(disableWith) !== null){\n if(DOM.isUploadInput(fromEl)){ DOM.mergeAttrs(fromEl, toEl, {isIgnored: true}) }\n DOM.putPrivate(fromEl, PHX_REF, toEl)\n return false\n } else {\n PHX_EVENT_CLASSES.forEach(className => {\n fromEl.classList.contains(className) && toEl.classList.add(className)\n })\n toEl.setAttribute(PHX_REF, ref)\n toEl.setAttribute(PHX_REF_SRC, refSrc)\n return true\n }\n },\n\n cleanChildNodes(container, phxUpdate){\n if(DOM.isPhxUpdate(container, phxUpdate, [\"append\", \"prepend\"])){\n let toRemove = []\n container.childNodes.forEach(childNode => {\n if(!childNode.id){\n // Skip warning if it's an empty text node (e.g. a new-line)\n let isEmptyTextNode = childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim() === \"\"\n if(!isEmptyTextNode){\n logError(\"only HTML element tags with an id are allowed inside containers with phx-update.\\n\\n\" +\n `removing illegal node: \"${(childNode.outerHTML || childNode.nodeValue).trim()}\"\\n\\n`)\n }\n toRemove.push(childNode)\n }\n })\n toRemove.forEach(childNode => childNode.remove())\n }\n },\n\n replaceRootContainer(container, tagName, attrs){\n let retainedAttrs = new Set([\"id\", PHX_SESSION, PHX_STATIC, PHX_MAIN, PHX_ROOT_ID])\n if(container.tagName.toLowerCase() === tagName.toLowerCase()){\n Array.from(container.attributes)\n .filter(attr => !retainedAttrs.has(attr.name.toLowerCase()))\n .forEach(attr => container.removeAttribute(attr.name))\n\n Object.keys(attrs)\n .filter(name => !retainedAttrs.has(name.toLowerCase()))\n .forEach(attr => container.setAttribute(attr, attrs[attr]))\n\n return container\n\n } else {\n let newContainer = document.createElement(tagName)\n Object.keys(attrs).forEach(attr => newContainer.setAttribute(attr, attrs[attr]))\n retainedAttrs.forEach(attr => newContainer.setAttribute(attr, container.getAttribute(attr)))\n newContainer.innerHTML = container.innerHTML\n container.replaceWith(newContainer)\n return newContainer\n }\n },\n\n getSticky(el, name, defaultVal){\n let op = (DOM.private(el, \"sticky\") || []).find(([existingName, ]) => name === existingName)\n if(op){\n let [_name, _op, stashedResult] = op\n return stashedResult\n } else {\n return typeof(defaultVal) === \"function\" ? defaultVal() : defaultVal\n }\n },\n\n deleteSticky(el, name){\n this.updatePrivate(el, \"sticky\", [], ops => {\n return ops.filter(([existingName, _]) => existingName !== name)\n })\n },\n\n putSticky(el, name, op){\n let stashedResult = op(el)\n this.updatePrivate(el, \"sticky\", [], ops => {\n let existingIndex = ops.findIndex(([existingName, ]) => name === existingName)\n if(existingIndex >= 0){\n ops[existingIndex] = [name, op, stashedResult]\n } else {\n ops.push([name, op, stashedResult])\n }\n return ops\n })\n },\n\n applyStickyOperations(el){\n let ops = DOM.private(el, \"sticky\")\n if(!ops){ return }\n\n ops.forEach(([name, op, _stashed]) => this.putSticky(el, name, op))\n }\n}\n\nexport default DOM\n", "import {\n PHX_ACTIVE_ENTRY_REFS,\n PHX_LIVE_FILE_UPDATED,\n PHX_PREFLIGHTED_REFS\n} from \"./constants\"\n\nimport {\n channelUploader,\n logError\n} from \"./utils\"\n\nimport LiveUploader from \"./live_uploader\"\n\nexport default class UploadEntry {\n static isActive(fileEl, file){\n let isNew = file._phxRef === undefined\n let activeRefs = fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(\",\")\n let isActive = activeRefs.indexOf(LiveUploader.genFileRef(file)) >= 0\n return file.size > 0 && (isNew || isActive)\n }\n\n static isPreflighted(fileEl, file){\n let preflightedRefs = fileEl.getAttribute(PHX_PREFLIGHTED_REFS).split(\",\")\n let isPreflighted = preflightedRefs.indexOf(LiveUploader.genFileRef(file)) >= 0\n return isPreflighted && this.isActive(fileEl, file)\n }\n\n constructor(fileEl, file, view){\n this.ref = LiveUploader.genFileRef(file)\n this.fileEl = fileEl\n this.file = file\n this.view = view\n this.meta = null\n this._isCancelled = false\n this._isDone = false\n this._progress = 0\n this._lastProgressSent = -1\n this._onDone = function (){ }\n this._onElUpdated = this.onElUpdated.bind(this)\n this.fileEl.addEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated)\n }\n\n metadata(){ return this.meta }\n\n progress(progress){\n this._progress = Math.floor(progress)\n if(this._progress > this._lastProgressSent){\n if(this._progress >= 100){\n this._progress = 100\n this._lastProgressSent = 100\n this._isDone = true\n this.view.pushFileProgress(this.fileEl, this.ref, 100, () => {\n LiveUploader.untrackFile(this.fileEl, this.file)\n this._onDone()\n })\n } else {\n this._lastProgressSent = this._progress\n this.view.pushFileProgress(this.fileEl, this.ref, this._progress)\n }\n }\n }\n\n cancel(){\n this._isCancelled = true\n this._isDone = true\n this._onDone()\n }\n\n isDone(){ return this._isDone }\n\n error(reason = \"failed\"){\n this.view.pushFileProgress(this.fileEl, this.ref, {error: reason})\n LiveUploader.clearFiles(this.fileEl)\n }\n\n //private\n\n onDone(callback){\n this._onDone = () => {\n this.fileEl.removeEventListener(PHX_LIVE_FILE_UPDATED, this._onElUpdated)\n callback()\n }\n }\n\n onElUpdated(){\n let activeRefs = this.fileEl.getAttribute(PHX_ACTIVE_ENTRY_REFS).split(\",\")\n if(activeRefs.indexOf(this.ref) === -1){ this.cancel() }\n }\n\n toPreflightPayload(){\n return {\n last_modified: this.file.lastModified,\n name: this.file.name,\n size: this.file.size,\n type: this.file.type,\n ref: this.ref\n }\n }\n\n uploader(uploaders){\n if(this.meta.uploader){\n let callback = uploaders[this.meta.uploader] || logError(`no uploader configured for ${this.meta.uploader}`)\n return {name: this.meta.uploader, callback: callback}\n } else {\n return {name: \"channel\", callback: channelUploader}\n }\n }\n\n zipPostFlight(resp){\n this.meta = resp.entries[this.ref]\n if(!this.meta){ logError(`no preflight upload response returned with ref ${this.ref}`, {input: this.fileEl, response: resp}) }\n }\n}\n", "import {\n PHX_DONE_REFS,\n PHX_PREFLIGHTED_REFS,\n PHX_UPLOAD_REF\n} from \"./constants\"\n\nimport {\n} from \"./utils\"\n\nimport DOM from \"./dom\"\nimport UploadEntry from \"./upload_entry\"\n\nlet liveUploaderFileRef = 0\n\nexport default class LiveUploader {\n static genFileRef(file){\n let ref = file._phxRef\n if(ref !== undefined){\n return ref\n } else {\n file._phxRef = (liveUploaderFileRef++).toString()\n return file._phxRef\n }\n }\n\n static getEntryDataURL(inputEl, ref, callback){\n let file = this.activeFiles(inputEl).find(file => this.genFileRef(file) === ref)\n callback(URL.createObjectURL(file))\n }\n\n static hasUploadsInProgress(formEl){\n let active = 0\n DOM.findUploadInputs(formEl).forEach(input => {\n if(input.getAttribute(PHX_PREFLIGHTED_REFS) !== input.getAttribute(PHX_DONE_REFS)){\n active++\n }\n })\n return active > 0\n }\n\n static serializeUploads(inputEl){\n let files = this.activeFiles(inputEl)\n let fileData = {}\n files.forEach(file => {\n let entry = {path: inputEl.name}\n let uploadRef = inputEl.getAttribute(PHX_UPLOAD_REF)\n fileData[uploadRef] = fileData[uploadRef] || []\n entry.ref = this.genFileRef(file)\n entry.name = file.name || entry.ref\n entry.type = file.type\n entry.size = file.size\n fileData[uploadRef].push(entry)\n })\n return fileData\n }\n\n static clearFiles(inputEl){\n inputEl.value = null\n inputEl.removeAttribute(PHX_UPLOAD_REF)\n DOM.putPrivate(inputEl, \"files\", [])\n }\n\n static untrackFile(inputEl, file){\n DOM.putPrivate(inputEl, \"files\", DOM.private(inputEl, \"files\").filter(f => !Object.is(f, file)))\n }\n\n static trackFiles(inputEl, files){\n if(inputEl.getAttribute(\"multiple\") !== null){\n let newFiles = files.filter(file => !this.activeFiles(inputEl).find(f => Object.is(f, file)))\n DOM.putPrivate(inputEl, \"files\", this.activeFiles(inputEl).concat(newFiles))\n inputEl.value = null\n } else {\n DOM.putPrivate(inputEl, \"files\", files)\n }\n }\n\n static activeFileInputs(formEl){\n let fileInputs = DOM.findUploadInputs(formEl)\n return Array.from(fileInputs).filter(el => el.files && this.activeFiles(el).length > 0)\n }\n\n static activeFiles(input){\n return (DOM.private(input, \"files\") || []).filter(f => UploadEntry.isActive(input, f))\n }\n\n static inputsAwaitingPreflight(formEl){\n let fileInputs = DOM.findUploadInputs(formEl)\n return Array.from(fileInputs).filter(input => this.filesAwaitingPreflight(input).length > 0)\n }\n\n static filesAwaitingPreflight(input){\n return this.activeFiles(input).filter(f => !UploadEntry.isPreflighted(input, f))\n }\n\n constructor(inputEl, view, onComplete){\n this.view = view\n this.onComplete = onComplete\n this._entries =\n Array.from(LiveUploader.filesAwaitingPreflight(inputEl) || [])\n .map(file => new UploadEntry(inputEl, file, view))\n\n this.numEntriesInProgress = this._entries.length\n }\n\n entries(){ return this._entries }\n\n initAdapterUpload(resp, onError, liveSocket){\n this._entries =\n this._entries.map(entry => {\n entry.zipPostFlight(resp)\n entry.onDone(() => {\n this.numEntriesInProgress--\n if(this.numEntriesInProgress === 0){ this.onComplete() }\n })\n return entry\n })\n\n let groupedEntries = this._entries.reduce((acc, entry) => {\n let {name, callback} = entry.uploader(liveSocket.uploaders)\n acc[name] = acc[name] || {callback: callback, entries: []}\n acc[name].entries.push(entry)\n return acc\n }, {})\n\n for(let name in groupedEntries){\n let {callback, entries} = groupedEntries[name]\n callback(entries, onError, resp, liveSocket)\n }\n }\n}\n", "import {\n PHX_ACTIVE_ENTRY_REFS,\n PHX_LIVE_FILE_UPDATED,\n PHX_PREFLIGHTED_REFS,\n PHX_UPLOAD_REF\n} from \"./constants\"\n\nimport LiveUploader from \"./live_uploader\"\n\nlet Hooks = {\n LiveFileUpload: {\n activeRefs(){ return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS) },\n\n preflightedRefs(){ return this.el.getAttribute(PHX_PREFLIGHTED_REFS) },\n\n mounted(){ this.preflightedWas = this.preflightedRefs() },\n\n updated(){\n let newPreflights = this.preflightedRefs()\n if(this.preflightedWas !== newPreflights){\n this.preflightedWas = newPreflights\n if(newPreflights === \"\"){\n this.__view.cancelSubmit(this.el.form)\n }\n }\n\n if(this.activeRefs() === \"\"){ this.el.value = null }\n this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED))\n }\n },\n\n LiveImgPreview: {\n mounted(){\n this.ref = this.el.getAttribute(\"data-phx-entry-ref\")\n this.inputEl = document.getElementById(this.el.getAttribute(PHX_UPLOAD_REF))\n LiveUploader.getEntryDataURL(this.inputEl, this.ref, url => {\n this.url = url\n this.el.src = url\n })\n },\n destroyed(){\n URL.revokeObjectURL(this.url)\n }\n }\n}\n\nexport default Hooks\n", "import {\n maybe\n} from \"./utils\"\n\nimport DOM from \"./dom\"\n\nexport default class DOMPostMorphRestorer {\n constructor(containerBefore, containerAfter, updateType){\n let idsBefore = new Set()\n let idsAfter = new Set([...containerAfter.children].map(child => child.id))\n\n let elementsToModify = []\n\n Array.from(containerBefore.children).forEach(child => {\n if(child.id){ // all of our children should be elements with ids\n idsBefore.add(child.id)\n if(idsAfter.has(child.id)){\n let previousElementId = child.previousElementSibling && child.previousElementSibling.id\n elementsToModify.push({elementId: child.id, previousElementId: previousElementId})\n }\n }\n })\n\n this.containerId = containerAfter.id\n this.updateType = updateType\n this.elementsToModify = elementsToModify\n this.elementIdsToAdd = [...idsAfter].filter(id => !idsBefore.has(id))\n }\n\n // We do the following to optimize append/prepend operations:\n // 1) Track ids of modified elements & of new elements\n // 2) All the modified elements are put back in the correct position in the DOM tree\n // by storing the id of their previous sibling\n // 3) New elements are going to be put in the right place by morphdom during append.\n // For prepend, we move them to the first position in the container\n perform(){\n let container = DOM.byId(this.containerId)\n this.elementsToModify.forEach(elementToModify => {\n if(elementToModify.previousElementId){\n maybe(document.getElementById(elementToModify.previousElementId), previousElem => {\n maybe(document.getElementById(elementToModify.elementId), elem => {\n let isInRightPlace = elem.previousElementSibling && elem.previousElementSibling.id == previousElem.id\n if(!isInRightPlace){\n previousElem.insertAdjacentElement(\"afterend\", elem)\n }\n })\n })\n } else {\n // This is the first element in the container\n maybe(document.getElementById(elementToModify.elementId), elem => {\n let isInRightPlace = elem.previousElementSibling == null\n if(!isInRightPlace){\n container.insertAdjacentElement(\"afterbegin\", elem)\n }\n })\n }\n })\n\n if(this.updateType == \"prepend\"){\n this.elementIdsToAdd.reverse().forEach(elemId => {\n maybe(document.getElementById(elemId), elem => container.insertAdjacentElement(\"afterbegin\", elem))\n })\n }\n }\n}\n", "var DOCUMENT_FRAGMENT_NODE = 11;\n\nfunction morphAttrs(fromNode, toNode) {\n var toNodeAttrs = toNode.attributes;\n var attr;\n var attrName;\n var attrNamespaceURI;\n var attrValue;\n var fromValue;\n\n // document-fragments dont have attributes so lets not do anything\n if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {\n return;\n }\n\n // update attributes on original DOM element\n for (var i = toNodeAttrs.length - 1; i >= 0; i--) {\n attr = toNodeAttrs[i];\n attrName = attr.name;\n attrNamespaceURI = attr.namespaceURI;\n attrValue = attr.value;\n\n if (attrNamespaceURI) {\n attrName = attr.localName || attrName;\n fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);\n\n if (fromValue !== attrValue) {\n if (attr.prefix === 'xmlns'){\n attrName = attr.name; // It's not allowed to set an attribute with the XMLNS namespace without specifying the `xmlns` prefix\n }\n fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);\n }\n } else {\n fromValue = fromNode.getAttribute(attrName);\n\n if (fromValue !== attrValue) {\n fromNode.setAttribute(attrName, attrValue);\n }\n }\n }\n\n // Remove any extra attributes found on the original DOM element that\n // weren't found on the target element.\n var fromNodeAttrs = fromNode.attributes;\n\n for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {\n attr = fromNodeAttrs[d];\n attrName = attr.name;\n attrNamespaceURI = attr.namespaceURI;\n\n if (attrNamespaceURI) {\n attrName = attr.localName || attrName;\n\n if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {\n fromNode.removeAttributeNS(attrNamespaceURI, attrName);\n }\n } else {\n if (!toNode.hasAttribute(attrName)) {\n fromNode.removeAttribute(attrName);\n }\n }\n }\n}\n\nvar range; // Create a range object for efficently rendering strings to elements.\nvar NS_XHTML = 'http://www.w3.org/1999/xhtml';\n\nvar doc = typeof document === 'undefined' ? undefined : document;\nvar HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template');\nvar HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange();\n\nfunction createFragmentFromTemplate(str) {\n var template = doc.createElement('template');\n template.innerHTML = str;\n return template.content.childNodes[0];\n}\n\nfunction createFragmentFromRange(str) {\n if (!range) {\n range = doc.createRange();\n range.selectNode(doc.body);\n }\n\n var fragment = range.createContextualFragment(str);\n return fragment.childNodes[0];\n}\n\nfunction createFragmentFromWrap(str) {\n var fragment = doc.createElement('body');\n fragment.innerHTML = str;\n return fragment.childNodes[0];\n}\n\n/**\n * This is about the same\n * var html = new DOMParser().parseFromString(str, 'text/html');\n * return html.body.firstChild;\n *\n * @method toElement\n * @param {String} str\n */\nfunction toElement(str) {\n str = str.trim();\n if (HAS_TEMPLATE_SUPPORT) {\n // avoid restrictions on content for things like `<tr><th>Hi</th></tr>` which\n // createContextualFragment doesn't support\n // <template> support not available in IE\n return createFragmentFromTemplate(str);\n } else if (HAS_RANGE_SUPPORT) {\n return createFragmentFromRange(str);\n }\n\n return createFragmentFromWrap(str);\n}\n\n/**\n * Returns true if two node's names are the same.\n *\n * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same\n * nodeName and different namespace URIs.\n *\n * @param {Element} a\n * @param {Element} b The target element\n * @return {boolean}\n */\nfunction compareNodeNames(fromEl, toEl) {\n var fromNodeName = fromEl.nodeName;\n var toNodeName = toEl.nodeName;\n var fromCodeStart, toCodeStart;\n\n if (fromNodeName === toNodeName) {\n return true;\n }\n\n fromCodeStart = fromNodeName.charCodeAt(0);\n toCodeStart = toNodeName.charCodeAt(0);\n\n // If the target element is a virtual DOM node or SVG node then we may\n // need to normalize the tag name before comparing. Normal HTML elements that are\n // in the \"http://www.w3.org/1999/xhtml\"\n // are converted to upper case\n if (fromCodeStart <= 90 && toCodeStart >= 97) { // from is upper and to is lower\n return fromNodeName === toNodeName.toUpperCase();\n } else if (toCodeStart <= 90 && fromCodeStart >= 97) { // to is upper and from is lower\n return toNodeName === fromNodeName.toUpperCase();\n } else {\n return false;\n }\n}\n\n/**\n * Create an element, optionally with a known namespace URI.\n *\n * @param {string} name the element name, e.g. 'div' or 'svg'\n * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of\n * its `xmlns` attribute or its inferred namespace.\n *\n * @return {Element}\n */\nfunction createElementNS(name, namespaceURI) {\n return !namespaceURI || namespaceURI === NS_XHTML ?\n doc.createElement(name) :\n doc.createElementNS(namespaceURI, name);\n}\n\n/**\n * Copies the children of one DOM element to another DOM element\n */\nfunction moveChildren(fromEl, toEl) {\n var curChild = fromEl.firstChild;\n while (curChild) {\n var nextChild = curChild.nextSibling;\n toEl.appendChild(curChild);\n curChild = nextChild;\n }\n return toEl;\n}\n\nfunction syncBooleanAttrProp(fromEl, toEl, name) {\n if (fromEl[name] !== toEl[name]) {\n fromEl[name] = toEl[name];\n if (fromEl[name]) {\n fromEl.setAttribute(name, '');\n } else {\n fromEl.removeAttribute(name);\n }\n }\n}\n\nvar specialElHandlers = {\n OPTION: function(fromEl, toEl) {\n var parentNode = fromEl.parentNode;\n if (parentNode) {\n var parentName = parentNode.nodeName.toUpperCase();\n if (parentName === 'OPTGROUP') {\n parentNode = parentNode.parentNode;\n parentName = parentNode && parentNode.nodeName.toUpperCase();\n }\n if (parentName === 'SELECT' && !parentNode.hasAttribute('multiple')) {\n if (fromEl.hasAttribute('selected') && !toEl.selected) {\n // Workaround for MS Edge bug where the 'selected' attribute can only be\n // removed if set to a non-empty value:\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12087679/\n fromEl.setAttribute('selected', 'selected');\n fromEl.removeAttribute('selected');\n }\n // We have to reset select element's selectedIndex to -1, otherwise setting\n // fromEl.selected using the syncBooleanAttrProp below has no effect.\n // The correct selectedIndex will be set in the SELECT special handler below.\n parentNode.selectedIndex = -1;\n }\n }\n syncBooleanAttrProp(fromEl, toEl, 'selected');\n },\n /**\n * The \"value\" attribute is special for the <input> element since it sets\n * the initial value. Changing the \"value\" attribute without changing the\n * \"value\" property will have no effect since it is only used to the set the\n * initial value. Similar for the \"checked\" attribute, and \"disabled\".\n */\n INPUT: function(fromEl, toEl) {\n syncBooleanAttrProp(fromEl, toEl, 'checked');\n syncBooleanAttrProp(fromEl, toEl, 'disabled');\n\n if (fromEl.value !== toEl.value) {\n fromEl.value = toEl.value;\n }\n\n if (!toEl.hasAttribute('value')) {\n fromEl.removeAttribute('value');\n }\n },\n\n TEXTAREA: function(fromEl, toEl) {\n var newValue = toEl.value;\n if (fromEl.value !== newValue) {\n fromEl.value = newValue;\n }\n\n var firstChild = fromEl.firstChild;\n if (firstChild) {\n // Needed for IE. Apparently IE sets the placeholder as the\n // node value and vise versa. This ignores an empty update.\n var oldValue = firstChild.nodeValue;\n\n if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {\n return;\n }\n\n firstChild.nodeValue = newValue;\n }\n },\n SELECT: function(fromEl, toEl) {\n if (!toEl.hasAttribute('multiple')) {\n var selectedIndex = -1;\n var i = 0;\n // We have to loop through children of fromEl, not toEl since nodes can be moved\n // from toEl to fromEl directly when morphing.\n // At the time this special handler is invoked, all children have already been morphed\n // and appended to / removed from fromEl, so using fromEl here is safe and correct.\n var curChild = fromEl.firstChild;\n var optgroup;\n var nodeName;\n while(curChild) {\n nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();\n if (nodeName === 'OPTGROUP') {\n optgroup = curChild;\n curChild = optgroup.firstChild;\n } else {\n if (nodeName === 'OPTION') {\n if (curChild.hasAttribute('selected')) {\n selectedIndex = i;\n break;\n }\n i++;\n }\n curChild = curChild.nextSibling;\n if (!curChild && optgroup) {\n curChild = optgroup.nextSibling;\n optgroup = null;\n }\n }\n }\n\n fromEl.selectedIndex = selectedIndex;\n }\n }\n};\n\nvar ELEMENT_NODE = 1;\nvar DOCUMENT_FRAGMENT_NODE$1 = 11;\nvar TEXT_NODE = 3;\nvar COMMENT_NODE = 8;\n\nfunction noop() {}\n\nfunction defaultGetNodeKey(node) {\n if (node) {\n return (node.getAttribute && node.getAttribute('id')) || node.id;\n }\n}\n\nfunction morphdomFactory(morphAttrs) {\n\n return function morphdom(fromNode, toNode, options) {\n if (!options) {\n options = {};\n }\n\n if (typeof toNode === 'string') {\n if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') {\n var toNodeHtml = toNode;\n toNode = doc.createElement('html');\n toNode.innerHTML = toNodeHtml;\n } else {\n toNode = toElement(toNode);\n }\n }\n\n var getNodeKey = options.getNodeKey || defaultGetNodeKey;\n var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;\n var onNodeAdded = options.onNodeAdded || noop;\n var onBeforeElUpdated = options.onBeforeElUpdated || noop;\n var onElUpdated = options.onElUpdated || noop;\n var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;\n var onNodeDiscarded = options.onNodeDiscarded || noop;\n var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;\n var childrenOnly = options.childrenOnly === true;\n\n // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.\n var fromNodesLookup = Object.create(null);\n var keyedRemovalList = [];\n\n function addKeyedRemoval(key) {\n keyedRemovalList.push(key);\n }\n\n function walkDiscardedChildNodes(node, skipKeyedNodes) {\n if (node.nodeType === ELEMENT_NODE) {\n var curChild = node.firstChild;\n while (curChild) {\n\n var key = undefined;\n\n if (skipKeyedNodes && (key = getNodeKey(curChild))) {\n // If we are skipping keyed nodes then we add the key\n // to a list so that it can be handled at the very end.\n addKeyedRemoval(key);\n } else {\n // Only report the node as discarded if it is not keyed. We do this because\n // at the end we loop through all keyed elements that were unmatched\n // and then discard them in one final pass.\n onNodeDiscarded(curChild);\n if (curChild.firstChild) {\n walkDiscardedChildNodes(curChild, skipKeyedNodes);\n }\n }\n\n curChild = curChild.nextSibling;\n }\n }\n }\n\n /**\n * Removes a DOM node out of the original DOM\n *\n * @param {Node} node The node to remove\n * @param {Node} parentNode The nodes parent\n * @param {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.\n * @return {undefined}\n */\n function removeNode(node, parentNode, skipKeyedNodes) {\n if (onBeforeNodeDiscarded(node) === false) {\n return;\n }\n\n if (parentNode) {\n parentNode.removeChild(node);\n }\n\n onNodeDiscarded(node);\n walkDiscardedChildNodes(node, skipKeyedNodes);\n }\n\n // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future\n // function indexTree(root) {\n // var treeWalker = document.createTreeWalker(\n // root,\n // NodeFilter.SHOW_ELEMENT);\n //\n // var el;\n // while((el = treeWalker.nextNode())) {\n // var key = getNodeKey(el);\n // if (key) {\n // fromNodesLookup[key] = el;\n // }\n // }\n // }\n\n // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future\n //\n // function indexTree(node) {\n // var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);\n // var el;\n // while((el = nodeIterator.nextNode())) {\n // var key = getNodeKey(el);\n // if (key) {\n // fromNodesLookup[key] = el;\n // }\n // }\n // }\n\n function indexTree(node) {\n if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {\n var curChild = node.firstChild;\n while (curChild) {\n var key = getNodeKey(curChild);\n if (key) {\n fromNodesLookup[key] = curChild;\n }\n\n // Walk recursively\n indexTree(curChild);\n\n curChild = curChild.nextSibling;\n }\n }\n }\n\n indexTree(fromNode);\n\n function handleNodeAdded(el) {\n onNodeAdded(el);\n\n var curChild = el.firstChild;\n while (curChild) {\n var nextSibling = curChild.nextSibling;\n\n var key = getNodeKey(curChild);\n if (key) {\n var unmatchedFromEl = fromNodesLookup[key];\n // if we find a duplicate #id node in cache, replace `el` with cache value\n // and morph it to the child node.\n if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {\n curChild.parentNode.replaceChild(unmatchedFromEl, curChild);\n morphEl(unmatchedFromEl, curChild);\n } else {\n handleNodeAdded(curChild);\n }\n } else {\n // recursively call for curChild and it's children to see if we find something in\n // fromNodesLookup\n handleNodeAdded(curChild);\n }\n\n curChild = nextSibling;\n }\n }\n\n function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {\n // We have processed all of the \"to nodes\". If curFromNodeChild is\n // non-null then we still have some from nodes left over that need\n // to be removed\n while (curFromNodeChild) {\n var fromNextSibling = curFromNodeChild.nextSibling;\n if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {\n // Since the node is keyed it might be matched up later so we defer\n // the actual removal to later\n addKeyedRemoval(curFromNodeKey);\n } else {\n // NOTE: we skip nested keyed nodes from being removed since there is\n // still a chance they will be matched up later\n removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);\n }\n curFromNodeChild = fromNextSibling;\n }\n }\n\n function morphEl(fromEl, toEl, childrenOnly) {\n var toElKey = getNodeKey(toEl);\n\n if (toElKey) {\n // If an element with an ID is being morphed then it will be in the final\n // DOM so clear it out of the saved elements collection\n delete fromNodesLookup[toElKey];\n }\n\n if (!childrenOnly) {\n // optional\n if (onBeforeElUpdated(fromEl, toEl) === false) {\n return;\n }\n\n // update attributes on original DOM element first\n morphAttrs(fromEl, toEl);\n // optional\n onElUpdated(fromEl);\n\n if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {\n return;\n }\n }\n\n if (fromEl.nodeName !== 'TEXTAREA') {\n morphChildren(fromEl, toEl);\n } else {\n specialElHandlers.TEXTAREA(fromEl, toEl);\n }\n }\n\n function morphChildren(fromEl, toEl) {\n var curToNodeChild = toEl.firstChild;\n var curFromNodeChild = fromEl.firstChild;\n var curToNodeKey;\n var curFromNodeKey;\n\n var fromNextSibling;\n var toNextSibling;\n var matchingFromEl;\n\n // walk the children\n outer: while (curToNodeChild) {\n toNextSibling = curToNodeChild.nextSibling;\n curToNodeKey = getNodeKey(curToNodeChild);\n\n // walk the fromNode children all the way through\n while (curFromNodeChild) {\n fromNextSibling = curFromNodeChild.nextSibling;\n\n if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {\n curToNodeChild = toNextSibling;\n curFromNodeChild = fromNextSibling;\n continue outer;\n }\n\n curFromNodeKey = getNodeKey(curFromNodeChild);\n\n var curFromNodeType = curFromNodeChild.nodeType;\n\n // this means if the curFromNodeChild doesnt have a match with the curToNodeChild\n var isCompatible = undefined;\n\n if (curFromNodeType === curToNodeChild.nodeType) {\n if (curFromNodeType === ELEMENT_NODE) {\n // Both nodes being compared are Element nodes\n\n if (curToNodeKey) {\n // The target node has a key so we want to match it up with the correct element\n // in the original DOM tree\n if (curToNodeKey !== curFromNodeKey) {\n // The current element in the original DOM tree does not have a matching key so\n // let's check our lookup to see if there is a matching element in the original\n // DOM tree\n if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {\n if (fromNextSibling === matchingFromEl) {\n // Special case for single element removals. To avoid removing the original\n // DOM node out of the tree (since that can break CSS transitions, etc.),\n // we will instead discard the current node and wait until the next\n // iteration to properly match up the keyed target element with its matching\n // element in the original tree\n isCompatible = false;\n } else {\n // We found a matching keyed element somewhere in the original DOM tree.\n // Let's move the original DOM node into the current position and morph\n // it.\n\n // NOTE: We use insertBefore instead of replaceChild because we want to go through\n // the `removeNode()` function for the node that is being discarded so that\n // all lifecycle hooks are correctly invoked\n fromEl.insertBefore(matchingFromEl, curFromNodeChild);\n\n // fromNextSibling = curFromNodeChild.nextSibling;\n\n if (curFromNodeKey) {\n // Since the node is keyed it might be matched up later so we defer\n // the actual removal to later\n addKeyedRemoval(curFromNodeKey);\n } else {\n // NOTE: we skip nested keyed nodes from being removed since there is\n // still a chance they will be matched up later\n removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);\n }\n\n curFromNodeChild = matchingFromEl;\n }\n } else {\n // The nodes are not compatible since the \"to\" node has a key and there\n // is no matching keyed node in the source tree\n isCompatible = false;\n }\n }\n } else if (curFromNodeKey) {\n // The original has a key\n isCompatible = false;\n }\n\n isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);\n if (isCompatible) {\n // We found compatible DOM elements so transform\n // the current \"from\" node to match the current\n // target DOM node.\n // MORPH\n morphEl(curFromNodeChild, curToNodeChild);\n }\n\n } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {\n // Both nodes being compared are Text or Comment nodes\n isCompatible = true;\n // Simply update nodeValue on the original node to\n // change the text value\n if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {\n curFromNodeChild.nodeValue = curToNodeChild.nodeValue;\n }\n\n }\n }\n\n if (isCompatible) {\n // Advance both the \"to\" child and the \"from\" child since we found a match\n // Nothing else to do as we already recursively called morphChildren above\n curToNodeChild = toNextSibling;\n curFromNodeChild = fromNextSibling;\n continue outer;\n }\n\n // No compatible match so remove the old node from the DOM and continue trying to find a\n // match in the original DOM. However, we only do this if the from node is not keyed\n // since it is possible that a keyed node might match up with a node somewhere else in the\n // target tree and we don't want to discard it just yet since it still might find a\n // home in the final DOM tree. After everything is done we will remove any keyed nodes\n // that didn't find a home\n if (curFromNodeKey) {\n // Since the node is keyed it might be matched up later so we defer\n // the actual removal to later\n addKeyedRemoval(curFromNodeKey);\n } else {\n // NOTE: we skip nested keyed nodes from being removed since there is\n // still a chance they will be matched up later\n removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);\n }\n\n curFromNodeChild = fromNextSibling;\n } // END: while(curFromNodeChild) {}\n\n // If we got this far then we did not find a candidate match for\n // our \"to node\" and we exhausted all of the children \"from\"\n // nodes. Therefore, we will just append the current \"to\" node\n // to the end\n if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {\n fromEl.appendChild(matchingFromEl);\n // MORPH\n morphEl(matchingFromEl, curToNodeChild);\n } else {\n var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);\n if (onBeforeNodeAddedResult !== false) {\n if (onBeforeNodeAddedResult) {\n curToNodeChild = onBeforeNodeAddedResult;\n }\n\n if (curToNodeChild.actualize) {\n curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);\n }\n fromEl.appendChild(curToNodeChild);\n handleNodeAdded(curToNodeChild);\n }\n }\n\n curToNodeChild = toNextSibling;\n curFromNodeChild = fromNextSibling;\n }\n\n cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);\n\n var specialElHandler = specialElHandlers[fromEl.nodeName];\n if (specialElHandler) {\n specialElHandler(fromEl, toEl);\n }\n } // END: morphChildren(...)\n\n var morphedNode = fromNode;\n var morphedNodeType = morphedNode.nodeType;\n var toNodeType = toNode.nodeType;\n\n if (!childrenOnly) {\n // Handle the case where we are given two DOM nodes that are not\n // compatible (e.g. <div> --> <span> or <div> --> TEXT)\n if (morphedNodeType === ELEMENT_NODE) {\n if (toNodeType === ELEMENT_NODE) {\n if (!compareNodeNames(fromNode, toNode)) {\n onNodeDiscarded(fromNode);\n morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));\n }\n } else {\n // Going from an element node to a text node\n morphedNode = toNode;\n }\n } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node\n if (toNodeType === morphedNodeType) {\n if (morphedNode.nodeValue !== toNode.nodeValue) {\n morphedNode.nodeValue = toNode.nodeValue;\n }\n\n return morphedNode;\n } else {\n // Text node to something else\n morphedNode = toNode;\n }\n }\n }\n\n if (morphedNode === toNode) {\n // The \"to node\" was not compatible with the \"from node\" so we had to\n // toss out the \"from node\" and use the \"to node\"\n onNodeDiscarded(fromNode);\n } else {\n if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {\n return;\n }\n\n morphEl(morphedNode, toNode, childrenOnly);\n\n // We now need to loop over any keyed nodes that might need to be\n // removed. We only do the removal if we know that the keyed node\n // never found a match. When a keyed node is matched up we remove\n // it out of fromNodesLookup and we use fromNodesLookup to determine\n // if a keyed node has been matched up or not\n if (keyedRemovalList) {\n for (var i=0, len=keyedRemovalList.length; i<len; i++) {\n var elToRemove = fromNodesLookup[keyedRemovalList[i]];\n if (elToRemove) {\n removeNode(elToRemove, elToRemove.parentNode, false);\n }\n }\n }\n }\n\n if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {\n if (morphedNode.actualize) {\n morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);\n }\n // If we had to swap out the from node with a new node because the old\n // node was not compatible with the target node then we need to\n // replace the old DOM node in the original DOM tree. This is only\n // possible if the original DOM node was part of a DOM tree which\n // we know is the case if it has a parent node.\n fromNode.parentNode.replaceChild(morphedNode, fromNode);\n }\n\n return morphedNode;\n };\n}\n\nvar morphdom = morphdomFactory(morphAttrs);\n\nexport default morphdom;\n", "import {\n PHX_COMPONENT,\n PHX_DISABLE_WITH,\n PHX_FEEDBACK_FOR,\n PHX_PRUNE,\n PHX_ROOT_ID,\n PHX_SESSION,\n PHX_SKIP,\n PHX_STATIC,\n PHX_TRIGGER_ACTION,\n PHX_UPDATE\n} from \"./constants\"\n\nimport {\n detectDuplicateIds,\n isCid\n} from \"./utils\"\n\nimport DOM from \"./dom\"\nimport DOMPostMorphRestorer from \"./dom_post_morph_restorer\"\nimport morphdom from \"morphdom\"\n\nexport default class DOMPatch {\n static patchEl(fromEl, toEl, activeElement){\n morphdom(fromEl, toEl, {\n childrenOnly: false,\n onBeforeElUpdated: (fromEl, toEl) => {\n if(activeElement && activeElement.isSameNode(fromEl) && DOM.isFormInput(fromEl)){\n DOM.mergeFocusedInput(fromEl, toEl)\n return false\n }\n }\n })\n }\n\n constructor(view, container, id, html, targetCID){\n this.view = view\n this.liveSocket = view.liveSocket\n this.container = container\n this.id = id\n this.rootID = view.root.id\n this.html = html\n this.targetCID = targetCID\n this.cidPatch = isCid(this.targetCID)\n this.callbacks = {\n beforeadded: [], beforeupdated: [], beforephxChildAdded: [],\n afteradded: [], afterupdated: [], afterdiscarded: [], afterphxChildAdded: [],\n aftertransitionsDiscarded: []\n }\n }\n\n before(kind, callback){ this.callbacks[`before${kind}`].push(callback) }\n after(kind, callback){ this.callbacks[`after${kind}`].push(callback) }\n\n trackBefore(kind, ...args){\n this.callbacks[`before${kind}`].forEach(callback => callback(...args))\n }\n\n trackAfter(kind, ...args){\n this.callbacks[`after${kind}`].forEach(callback => callback(...args))\n }\n\n markPrunableContentForRemoval(){\n DOM.all(this.container, \"[phx-update=append] > *, [phx-update=prepend] > *\", el => {\n el.setAttribute(PHX_PRUNE, \"\")\n })\n }\n\n perform(){\n let {view, liveSocket, container, html} = this\n let targetContainer = this.isCIDPatch() ? this.targetCIDContainer(html) : container\n if(this.isCIDPatch() && !targetContainer){ return }\n\n let focused = liveSocket.getActiveElement()\n let {selectionStart, selectionEnd} = focused && DOM.hasSelectionRange(focused) ? focused : {}\n let phxUpdate = liveSocket.binding(PHX_UPDATE)\n let phxFeedbackFor = liveSocket.binding(PHX_FEEDBACK_FOR)\n let disableWith = liveSocket.binding(PHX_DISABLE_WITH)\n let phxTriggerExternal = liveSocket.binding(PHX_TRIGGER_ACTION)\n let phxRemove = liveSocket.binding(\"remove\")\n let added = []\n let updates = []\n let appendPrependUpdates = []\n let pendingRemoves = []\n let externalFormTriggered = null\n\n let diffHTML = liveSocket.time(\"premorph container prep\", () => {\n return this.buildDiffHTML(container, html, phxUpdate, targetContainer)\n })\n\n this.trackBefore(\"added\", container)\n this.trackBefore(\"updated\", container, container)\n\n liveSocket.time(\"morphdom\", () => {\n morphdom(targetContainer, diffHTML, {\n childrenOnly: targetContainer.getAttribute(PHX_COMPONENT) === null,\n getNodeKey: (node) => {\n return DOM.isPhxDestroyed(node) ? null : node.id\n },\n onBeforeNodeAdded: (el) => {\n this.trackBefore(\"added\", el)\n return el\n },\n onNodeAdded: (el) => {\n // hack to fix Safari handling of img srcset and video tags\n if(el instanceof HTMLImageElement && el.srcset){\n el.srcset = el.srcset\n } else if(el instanceof HTMLVideoElement && el.autoplay){\n el.play()\n }\n if(DOM.isNowTriggerFormExternal(el, phxTriggerExternal)){\n externalFormTriggered = el\n }\n //input handling\n DOM.discardError(targetContainer, el, phxFeedbackFor)\n // nested view handling\n if((DOM.isPhxChild(el) && view.ownsElement(el)) || DOM.isPhxSticky(el) && view.ownsElement(el.parentNode)){\n this.trackAfter(\"phxChildAdded\", el)\n }\n added.push(el)\n },\n onNodeDiscarded: (el) => {\n // nested view handling\n if(DOM.isPhxChild(el) || DOM.isPhxSticky(el)){ liveSocket.destroyViewByEl(el) }\n this.trackAfter(\"discarded\", el)\n },\n onBeforeNodeDiscarded: (el) => {\n if(el.getAttribute && el.getAttribute(PHX_PRUNE) !== null){ return true }\n if(el.parentNode !== null && DOM.isPhxUpdate(el.parentNode, phxUpdate, [\"append\", \"prepend\"]) && el.id){ return false }\n if(el.getAttribute && el.getAttribute(phxRemove)){\n pendingRemoves.push(el)\n return false\n }\n if(this.skipCIDSibling(el)){ return false }\n return true\n },\n onElUpdated: (el) => {\n if(DOM.isNowTriggerFormExternal(el, phxTriggerExternal)){\n externalFormTriggered = el\n }\n updates.push(el)\n },\n onBeforeElUpdated: (fromEl, toEl) => {\n DOM.cleanChildNodes(toEl, phxUpdate)\n if(this.skipCIDSibling(toEl)){ return false }\n if(DOM.isPhxSticky(fromEl)){ return false }\n if(DOM.isIgnored(fromEl, phxUpdate)){\n this.trackBefore(\"updated\", fromEl, toEl)\n DOM.mergeAttrs(fromEl, toEl, {isIgnored: true})\n updates.push(fromEl)\n DOM.applyStickyOperations(fromEl)\n return false\n }\n if(fromEl.type === \"number\" && (fromEl.validity && fromEl.validity.badInput)){ return false }\n if(!DOM.syncPendingRef(fromEl, toEl, disableWith)){\n if(DOM.isUploadInput(fromEl)){\n this.trackBefore(\"updated\", fromEl, toEl)\n updates.push(fromEl)\n }\n DOM.applyStickyOperations(fromEl)\n return false\n }\n\n // nested view handling\n if(DOM.isPhxChild(toEl)){\n let prevSession = fromEl.getAttribute(PHX_SESSION)\n DOM.mergeAttrs(fromEl, toEl, {exclude: [PHX_STATIC]})\n if(prevSession !== \"\"){ fromEl.setAttribute(PHX_SESSION, prevSession) }\n fromEl.setAttribute(PHX_ROOT_ID, this.rootID)\n DOM.applyStickyOperations(fromEl)\n return false\n }\n\n // input handling\n DOM.copyPrivates(toEl, fromEl)\n DOM.discardError(targetContainer, toEl, phxFeedbackFor)\n\n let isFocusedFormEl = focused && fromEl.isSameNode(focused) && DOM.isFormInput(fromEl)\n if(isFocusedFormEl){\n this.trackBefore(\"updated\", fromEl, toEl)\n DOM.mergeFocusedInput(fromEl, toEl)\n DOM.syncAttrsToProps(fromEl)\n updates.push(fromEl)\n DOM.applyStickyOperations(fromEl)\n return false\n } else {\n if(DOM.isPhxUpdate(toEl, phxUpdate, [\"append\", \"prepend\"])){\n appendPrependUpdates.push(new DOMPostMorphRestorer(fromEl, toEl, toEl.getAttribute(phxUpdate)))\n }\n DOM.syncAttrsToProps(toEl)\n DOM.applyStickyOperations(toEl)\n this.trackBefore(\"updated\", fromEl, toEl)\n return true\n }\n }\n })\n })\n\n if(liveSocket.isDebugEnabled()){ detectDuplicateIds() }\n\n if(appendPrependUpdates.length > 0){\n liveSocket.time(\"post-morph append/prepend restoration\", () => {\n appendPrependUpdates.forEach(update => update.perform())\n })\n }\n\n liveSocket.silenceEvents(() => DOM.restoreFocus(focused, selectionStart, selectionEnd))\n DOM.dispatchEvent(document, \"phx:update\")\n added.forEach(el => this.trackAfter(\"added\", el))\n updates.forEach(el => this.trackAfter(\"updated\", el))\n\n if(pendingRemoves.length > 0){\n liveSocket.transitionRemoves(pendingRemoves)\n liveSocket.requestDOMUpdate(() => {\n pendingRemoves.forEach(el => {\n let child = DOM.firstPhxChild(el)\n if(child){ liveSocket.destroyViewByEl(child) }\n el.remove()\n })\n this.trackAfter(\"transitionsDiscarded\", pendingRemoves)\n })\n }\n\n if(externalFormTriggered){\n liveSocket.disconnect()\n externalFormTriggered.submit()\n }\n return true\n }\n\n isCIDPatch(){ return this.cidPatch }\n\n skipCIDSibling(el){\n return el.nodeType === Node.ELEMENT_NODE && el.getAttribute(PHX_SKIP) !== null\n }\n\n targetCIDContainer(html){\n if(!this.isCIDPatch()){ return }\n let [first, ...rest] = DOM.findComponentNodeList(this.container, this.targetCID)\n if(rest.length === 0 && DOM.childNodeLength(html) === 1){\n return first\n } else {\n return first && first.parentNode\n }\n }\n\n // builds HTML for morphdom patch\n // - for full patches of LiveView or a component with a single\n // root node, simply returns the HTML\n // - for patches of a component with multiple root nodes, the\n // parent node becomes the target container and non-component\n // siblings are marked as skip.\n buildDiffHTML(container, html, phxUpdate, targetContainer){\n let isCIDPatch = this.isCIDPatch()\n let isCIDWithSingleRoot = isCIDPatch && targetContainer.getAttribute(PHX_COMPONENT) === this.targetCID.toString()\n if(!isCIDPatch || isCIDWithSingleRoot){\n return html\n } else {\n // component patch with multiple CID roots\n let diffContainer = null\n let template = document.createElement(\"template\")\n diffContainer = DOM.cloneNode(targetContainer)\n let [firstComponent, ...rest] = DOM.findComponentNodeList(diffContainer, this.targetCID)\n template.innerHTML = html\n rest.forEach(el => el.remove())\n Array.from(diffContainer.childNodes).forEach(child => {\n // we can only skip trackable nodes with an ID\n if(child.id && child.nodeType === Node.ELEMENT_NODE && child.getAttribute(PHX_COMPONENT) !== this.targetCID.toString()){\n child.setAttribute(PHX_SKIP, \"\")\n child.innerHTML = \"\"\n }\n })\n Array.from(template.content.childNodes).forEach(el => diffContainer.insertBefore(el, firstComponent))\n firstComponent.remove()\n return diffContainer.outerHTML\n }\n }\n}\n", "import {\n COMPONENTS,\n DYNAMICS,\n TEMPLATES,\n EVENTS,\n PHX_COMPONENT,\n PHX_SKIP,\n REPLY,\n STATIC,\n TITLE\n} from \"./constants\"\n\nimport {\n isObject,\n logError,\n isCid,\n} from \"./utils\"\n\nexport default class Rendered {\n static extract(diff){\n let {[REPLY]: reply, [EVENTS]: events, [TITLE]: title} = diff\n delete diff[REPLY]\n delete diff[EVENTS]\n delete diff[TITLE]\n return {diff, title, reply: reply || null, events: events || []}\n }\n\n constructor(viewId, rendered){\n this.viewId = viewId\n this.rendered = {}\n this.mergeDiff(rendered)\n }\n\n parentViewId(){ return this.viewId }\n\n toString(onlyCids){\n return this.recursiveToString(this.rendered, this.rendered[COMPONENTS], onlyCids)\n }\n\n recursiveToString(rendered, components = rendered[COMPONENTS], onlyCids){\n onlyCids = onlyCids ? new Set(onlyCids) : null\n let output = {buffer: \"\", components: components, onlyCids: onlyCids}\n this.toOutputBuffer(rendered, null, output)\n return output.buffer\n }\n\n componentCIDs(diff){ return Object.keys(diff[COMPONENTS] || {}).map(i => parseInt(i)) }\n\n isComponentOnlyDiff(diff){\n if(!diff[COMPONENTS]){ return false }\n return Object.keys(diff).length === 1\n }\n\n getComponent(diff, cid){ return diff[COMPONENTS][cid] }\n\n mergeDiff(diff){\n let newc = diff[COMPONENTS]\n let cache = {}\n delete diff[COMPONENTS]\n this.rendered = this.mutableMerge(this.rendered, diff)\n this.rendered[COMPONENTS] = this.rendered[COMPONENTS] || {}\n\n if(newc){\n let oldc = this.rendered[COMPONENTS]\n\n for(let cid in newc){\n newc[cid] = this.cachedFindComponent(cid, newc[cid], oldc, newc, cache)\n }\n\n for(let cid in newc){ oldc[cid] = newc[cid] }\n diff[COMPONENTS] = newc\n }\n }\n\n cachedFindComponent(cid, cdiff, oldc, newc, cache){\n if(cache[cid]){\n return cache[cid]\n } else {\n let ndiff, stat, scid = cdiff[STATIC]\n\n if(isCid(scid)){\n let tdiff\n\n if(scid > 0){\n tdiff = this.cachedFindComponent(scid, newc[scid], oldc, newc, cache)\n } else {\n tdiff = oldc[-scid]\n }\n\n stat = tdiff[STATIC]\n ndiff = this.cloneMerge(tdiff, cdiff)\n ndiff[STATIC] = stat\n } else {\n ndiff = cdiff[STATIC] !== undefined ? cdiff : this.cloneMerge(oldc[cid] || {}, cdiff)\n }\n\n cache[cid] = ndiff\n return ndiff\n }\n }\n\n mutableMerge(target, source){\n if(source[STATIC] !== undefined){\n return source\n } else {\n this.doMutableMerge(target, source)\n return target\n }\n }\n\n doMutableMerge(target, source){\n for(let key in source){\n let val = source[key]\n let targetVal = target[key]\n if(isObject(val) && val[STATIC] === undefined && isObject(targetVal)){\n this.doMutableMerge(targetVal, val)\n } else {\n target[key] = val\n }\n }\n }\n\n cloneMerge(target, source){\n let merged = {...target, ...source}\n for(let key in merged){\n let val = source[key]\n let targetVal = target[key]\n if(isObject(val) && val[STATIC] === undefined && isObject(targetVal)){\n merged[key] = this.cloneMerge(targetVal, val)\n }\n }\n return merged\n }\n\n componentToString(cid){ return this.recursiveCIDToString(this.rendered[COMPONENTS], cid) }\n\n pruneCIDs(cids){\n cids.forEach(cid => delete this.rendered[COMPONENTS][cid])\n }\n\n // private\n\n get(){ return this.rendered }\n\n isNewFingerprint(diff = {}){ return !!diff[STATIC] }\n\n templateStatic(part, templates){\n if(typeof (part) === \"number\") {\n return templates[part]\n } else {\n return part\n }\n }\n\n toOutputBuffer(rendered, templates, output){\n if(rendered[DYNAMICS]){ return this.comprehensionToBuffer(rendered, templates, output) }\n let {[STATIC]: statics} = rendered\n statics = this.templateStatic(statics, templates)\n\n output.buffer += statics[0]\n for(let i = 1; i < statics.length; i++){\n this.dynamicToBuffer(rendered[i - 1], templates, output)\n output.buffer += statics[i]\n }\n }\n\n comprehensionToBuffer(rendered, templates, output){\n let {[DYNAMICS]: dynamics, [STATIC]: statics} = rendered\n statics = this.templateStatic(statics, templates)\n let compTemplates = templates || rendered[TEMPLATES]\n\n for(let d = 0; d < dynamics.length; d++){\n let dynamic = dynamics[d]\n output.buffer += statics[0]\n for(let i = 1; i < statics.length; i++){\n this.dynamicToBuffer(dynamic[i - 1], compTemplates, output)\n output.buffer += statics[i]\n }\n }\n }\n\n dynamicToBuffer(rendered, templates, output){\n if(typeof (rendered) === \"number\"){\n output.buffer += this.recursiveCIDToString(output.components, rendered, output.onlyCids)\n } else if(isObject(rendered)){\n this.toOutputBuffer(rendered, templates, output)\n } else {\n output.buffer += rendered\n }\n }\n\n recursiveCIDToString(components, cid, onlyCids){\n let component = components[cid] || logError(`no component for CID ${cid}`, components)\n let template = document.createElement(\"template\")\n template.innerHTML = this.recursiveToString(component, components, onlyCids)\n let container = template.content\n let skip = onlyCids && !onlyCids.has(cid)\n\n let [hasChildNodes, hasChildComponents] =\n Array.from(container.childNodes).reduce(([hasNodes, hasComponents], child, i) => {\n if(child.nodeType === Node.ELEMENT_NODE){\n if(child.getAttribute(PHX_COMPONENT)){\n return [hasNodes, true]\n }\n child.setAttribute(PHX_COMPONENT, cid)\n if(!child.id){ child.id = `${this.parentViewId()}-${cid}-${i}` }\n if(skip){\n child.setAttribute(PHX_SKIP, \"\")\n child.innerHTML = \"\"\n }\n return [true, hasComponents]\n } else {\n if(child.nodeValue.trim() !== \"\"){\n logError(\"only HTML element tags are allowed at the root of components.\\n\\n\" +\n `got: \"${child.nodeValue.trim()}\"\\n\\n` +\n \"within:\\n\", template.innerHTML.trim())\n child.replaceWith(this.createSpan(child.nodeValue, cid))\n return [true, hasComponents]\n } else {\n child.remove()\n return [hasNodes, hasComponents]\n }\n }\n }, [false, false])\n\n if(!hasChildNodes && !hasChildComponents){\n logError(\"expected at least one HTML element tag inside a component, but the component is empty:\\n\",\n template.innerHTML.trim())\n return this.createSpan(\"\", cid).outerHTML\n } else if(!hasChildNodes && hasChildComponents){\n logError(\"expected at least one HTML element tag directly inside a component, but only subcomponents were found. A component must render at least one HTML tag directly inside itself.\",\n template.innerHTML.trim())\n return template.innerHTML\n } else {\n return template.innerHTML\n }\n }\n\n createSpan(text, cid){\n let span = document.createElement(\"span\")\n span.innerText = text\n span.setAttribute(PHX_COMPONENT, cid)\n return span\n }\n}\n", "let viewHookID = 1\nexport default class ViewHook {\n static makeID(){ return viewHookID++ }\n static elementID(el){ return el.phxHookId }\n\n constructor(view, el, callbacks){\n this.__view = view\n this.liveSocket = view.liveSocket\n this.__callbacks = callbacks\n this.__listeners = new Set()\n this.__isDisconnected = false\n this.el = el\n this.el.phxHookId = this.constructor.makeID()\n for(let key in this.__callbacks){ this[key] = this.__callbacks[key] }\n }\n\n __mounted(){ this.mounted && this.mounted() }\n __updated(){ this.updated && this.updated() }\n __beforeUpdate(){ this.beforeUpdate && this.beforeUpdate() }\n __destroyed(){ this.destroyed && this.destroyed() }\n __reconnected(){\n if(this.__isDisconnected){\n this.__isDisconnected = false\n this.reconnected && this.reconnected()\n }\n }\n __disconnected(){\n this.__isDisconnected = true\n this.disconnected && this.disconnected()\n }\n\n pushEvent(event, payload = {}, onReply = function (){ }){\n return this.__view.pushHookEvent(null, event, payload, onReply)\n }\n\n pushEventTo(phxTarget, event, payload = {}, onReply = function (){ }){\n return this.__view.withinTargets(phxTarget, (view, targetCtx) => {\n return view.pushHookEvent(targetCtx, event, payload, onReply)\n })\n }\n\n handleEvent(event, callback){\n let callbackRef = (customEvent, bypass) => bypass ? event : callback(customEvent.detail)\n window.addEventListener(`phx:${event}`, callbackRef)\n this.__listeners.add(callbackRef)\n return callbackRef\n }\n\n removeHandleEvent(callbackRef){\n let event = callbackRef(null, true)\n window.removeEventListener(`phx:${event}`, callbackRef)\n this.__listeners.delete(callbackRef)\n }\n\n upload(name, files){\n return this.__view.dispatchUploads(name, files)\n }\n\n uploadTo(phxTarget, name, files){\n return this.__view.withinTargets(phxTarget, view => view.dispatchUploads(name, files))\n }\n\n __cleanup__(){\n this.__listeners.forEach(callbackRef => this.removeHandleEvent(callbackRef))\n }\n}\n", "import DOM from \"./dom\"\n\nlet JS = {\n exec(eventType, phxEvent, view, sourceEl, defaults){\n let [defaultKind, defaultArgs] = defaults || [null, {}]\n let commands = phxEvent.charAt(0) === \"[\" ?\n JSON.parse(phxEvent) : [[defaultKind, defaultArgs]]\n\n commands.forEach(([kind, args]) => {\n if(kind === defaultKind && defaultArgs.data){\n args.data = Object.assign(args.data || {}, defaultArgs.data)\n }\n this.filterToEls(sourceEl, args).forEach(el => {\n this[`exec_${kind}`](eventType, phxEvent, view, sourceEl, el, args)\n })\n })\n },\n\n isVisible(el){\n return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length > 0)\n },\n\n // private\n\n // commands\n\n exec_dispatch(eventType, phxEvent, view, sourceEl, el, {to, event, detail, bubbles}){\n detail = detail || {}\n detail.dispatcher = sourceEl\n DOM.dispatchEvent(el, event, {detail, bubbles})\n },\n\n exec_push(eventType, phxEvent, view, sourceEl, el, args){\n if(!view.isConnected()){ return }\n\n let {event, data, target, page_loading, loading, value, dispatcher} = args\n let pushOpts = {loading, value, target, page_loading: !!page_loading}\n let targetSrc = eventType === \"change\" && dispatcher ? dispatcher : sourceEl\n let phxTarget = target || targetSrc.getAttribute(view.binding(\"target\")) || targetSrc\n view.withinTargets(phxTarget, (targetView, targetCtx) => {\n if(eventType === \"change\"){\n let {newCid, _target, callback} = args\n _target = _target || (sourceEl instanceof HTMLInputElement ? sourceEl.name : undefined)\n if(_target){ pushOpts._target = _target }\n targetView.pushInput(sourceEl, targetCtx, newCid, event || phxEvent, pushOpts, callback)\n } else if(eventType === \"submit\"){\n targetView.submitForm(sourceEl, targetCtx, event || phxEvent, pushOpts)\n } else {\n targetView.pushEvent(eventType, sourceEl, targetCtx, event || phxEvent, data, pushOpts)\n }\n })\n },\n\n exec_add_class(eventType, phxEvent, view, sourceEl, el, {names, transition, time}){\n this.addOrRemoveClasses(el, names, [], transition, time, view)\n },\n\n exec_remove_class(eventType, phxEvent, view, sourceEl, el, {names, transition, time}){\n this.addOrRemoveClasses(el, [], names, transition, time, view)\n },\n\n exec_transition(eventType, phxEvent, view, sourceEl, el, {time, transition}){\n let [transition_start, running, transition_end] = transition\n let onStart = () => this.addOrRemoveClasses(el, transition_start.concat(running), [])\n let onDone = () => this.addOrRemoveClasses(el, transition_end, transition_start.concat(running))\n view.transition(time, onStart, onDone)\n },\n\n exec_toggle(eventType, phxEvent, view, sourceEl, el, {display, ins, outs, time}){\n this.toggle(eventType, view, el, display, ins, outs, time)\n },\n\n exec_show(eventType, phxEvent, view, sourceEl, el, {display, transition, time}){\n this.show(eventType, view, el, display, transition, time)\n },\n\n exec_hide(eventType, phxEvent, view, sourceEl, el, {display, transition, time}){\n this.hide(eventType, view, el, display, transition, time)\n },\n\n exec_set_attr(eventType, phxEvent, view, sourceEl, el, {attr: [attr, val]}){\n this.setOrRemoveAttrs(el, [[attr, val]], [])\n },\n\n exec_remove_attr(eventType, phxEvent, view, sourceEl, el, {attr}){\n this.setOrRemoveAttrs(el, [], [attr])\n },\n\n // utils for commands\n\n show(eventType, view, el, display, transition, time){\n if(!this.isVisible(el)){\n this.toggle(eventType, view, el, display, transition, null, time)\n }\n },\n\n hide(eventType, view, el, display, transition, time){\n if(this.isVisible(el)){\n this.toggle(eventType, view, el, display, null, transition, time)\n }\n },\n\n toggle(eventType, view, el, display, ins, outs, time){\n let [inClasses, inStartClasses, inEndClasses] = ins || [[], [], []]\n let [outClasses, outStartClasses, outEndClasses] = outs || [[], [], []]\n if(inClasses.length > 0 || outClasses.length > 0){\n if(this.isVisible(el)){\n let onStart = () => {\n this.addOrRemoveClasses(el, outStartClasses, inClasses.concat(inStartClasses).concat(inEndClasses))\n window.requestAnimationFrame(() => {\n this.addOrRemoveClasses(el, outClasses, [])\n window.requestAnimationFrame(() => this.addOrRemoveClasses(el, outEndClasses, outStartClasses))\n })\n }\n el.dispatchEvent(new Event(\"phx:hide-start\"))\n view.transition(time, onStart, () => {\n this.addOrRemoveClasses(el, [], outClasses.concat(outEndClasses))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = \"none\")\n el.dispatchEvent(new Event(\"phx:hide-end\"))\n })\n } else {\n if(eventType === \"remove\"){ return }\n let onStart = () => {\n this.addOrRemoveClasses(el, inStartClasses, outClasses.concat(outStartClasses).concat(outEndClasses))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = (display || \"block\"))\n window.requestAnimationFrame(() => {\n this.addOrRemoveClasses(el, inClasses, [])\n window.requestAnimationFrame(() => this.addOrRemoveClasses(el, inEndClasses, inStartClasses))\n })\n }\n el.dispatchEvent(new Event(\"phx:show-start\"))\n view.transition(time, onStart, () => {\n this.addOrRemoveClasses(el, [], inClasses.concat(inEndClasses))\n el.dispatchEvent(new Event(\"phx:show-end\"))\n })\n }\n } else {\n if(this.isVisible(el)){\n window.requestAnimationFrame(() => {\n el.dispatchEvent(new Event(\"phx:hide-start\"))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = \"none\")\n el.dispatchEvent(new Event(\"phx:hide-end\"))\n })\n } else {\n window.requestAnimationFrame(() => {\n el.dispatchEvent(new Event(\"phx:show-start\"))\n DOM.putSticky(el, \"toggle\", currentEl => currentEl.style.display = display || \"block\")\n el.dispatchEvent(new Event(\"phx:show-end\"))\n })\n }\n }\n },\n\n addOrRemoveClasses(el, adds, removes, transition, time, view){\n let [transition_run, transition_start, transition_end] = transition || [[], [], []]\n if(transition_run.length > 0){\n let onStart = () => this.addOrRemoveClasses(el, transition_start.concat(transition_run), [])\n let onDone = () => this.addOrRemoveClasses(el, adds.concat(transition_end), removes.concat(transition_run).concat(transition_start))\n return view.transition(time, onStart, onDone)\n }\n window.requestAnimationFrame(() => {\n let [prevAdds, prevRemoves] = DOM.getSticky(el, \"classes\", [[], []])\n let keepAdds = adds.filter(name => prevAdds.indexOf(name) < 0 && !el.classList.contains(name))\n let keepRemoves = removes.filter(name => prevRemoves.indexOf(name) < 0 && el.classList.contains(name))\n let newAdds = prevAdds.filter(name => removes.indexOf(name) < 0).concat(keepAdds)\n let newRemoves = prevRemoves.filter(name => adds.indexOf(name) < 0).concat(keepRemoves)\n\n DOM.putSticky(el, \"classes\", currentEl => {\n currentEl.classList.remove(...newRemoves)\n currentEl.classList.add(...newAdds)\n return [newAdds, newRemoves]\n })\n })\n },\n\n setOrRemoveAttrs(el, sets, removes){\n let [prevSets, prevRemoves] = DOM.getSticky(el, \"attrs\", [[], []])\n\n let alteredAttrs = sets.map(([attr, _val]) => attr).concat(removes);\n let newSets = prevSets.filter(([attr, _val]) => !alteredAttrs.includes(attr)).concat(sets);\n let newRemoves = prevRemoves.filter((attr) => !alteredAttrs.includes(attr)).concat(removes);\n\n DOM.putSticky(el, \"attrs\", currentEl => {\n newRemoves.forEach(attr => currentEl.removeAttribute(attr))\n newSets.forEach(([attr, val]) => currentEl.setAttribute(attr, val))\n return [newSets, newRemoves]\n })\n },\n\n hasAllClasses(el, classes){ return classes.every(name => el.classList.contains(name)) },\n\n isToggledOut(el, outClasses){\n return !this.isVisible(el) || this.hasAllClasses(el, outClasses)\n },\n\n filterToEls(sourceEl, {to}){\n return to ? DOM.all(document, to) : [sourceEl]\n }\n}\n\nexport default JS\n", "import {\n BEFORE_UNLOAD_LOADER_TIMEOUT,\n CHECKABLE_INPUTS,\n CONSECUTIVE_RELOADS,\n PHX_AUTO_RECOVER,\n PHX_COMPONENT,\n PHX_CONNECTED_CLASS,\n PHX_DISABLE_WITH,\n PHX_DISABLE_WITH_RESTORE,\n PHX_DISABLED,\n PHX_DISCONNECTED_CLASS,\n PHX_EVENT_CLASSES,\n PHX_ERROR_CLASS,\n PHX_FEEDBACK_FOR,\n PHX_HAS_SUBMITTED,\n PHX_HOOK,\n PHX_PAGE_LOADING,\n PHX_PARENT_ID,\n PHX_PROGRESS,\n PHX_READONLY,\n PHX_REF,\n PHX_REF_SRC,\n PHX_ROOT_ID,\n PHX_SESSION,\n PHX_STATIC,\n PHX_TRACK_STATIC,\n PHX_TRACK_UPLOADS,\n PHX_UPDATE,\n PHX_UPLOAD_REF,\n PHX_VIEW_SELECTOR,\n PUSH_TIMEOUT,\n PHX_MAIN,\n} from \"./constants\"\n\nimport {\n clone,\n closestPhxBinding,\n isEmpty,\n isEqualObj,\n logError,\n maybe,\n isCid,\n} from \"./utils\"\n\nimport Browser from \"./browser\"\nimport DOM from \"./dom\"\nimport DOMPatch from \"./dom_patch\"\nimport LiveUploader from \"./live_uploader\"\nimport Rendered from \"./rendered\"\nimport ViewHook from \"./view_hook\"\nimport JS from \"./js\"\n\nlet serializeForm = (form, meta, onlyNames = []) => {\n let formData = new FormData(form)\n let toRemove = []\n\n formData.forEach((val, key, _index) => {\n if(val instanceof File){ toRemove.push(key) }\n })\n\n // Cleanup after building fileData\n toRemove.forEach(key => formData.delete(key))\n\n let params = new URLSearchParams()\n for(let [key, val] of formData.entries()){\n if(onlyNames.length === 0 || onlyNames.indexOf(key) >= 0){\n params.append(key, val)\n }\n }\n for(let metaKey in meta){ params.append(metaKey, meta[metaKey]) }\n\n return params.toString()\n}\n\nexport default class View {\n constructor(el, liveSocket, parentView, flash){\n this.liveSocket = liveSocket\n this.flash = flash\n this.parent = parentView\n this.root = parentView ? parentView.root : this\n this.el = el\n this.id = this.el.id\n this.ref = 0\n this.childJoins = 0\n this.loaderTimer = null\n this.pendingDiffs = []\n this.pruningCIDs = []\n this.redirect = false\n this.href = null\n this.joinCount = this.parent ? this.parent.joinCount - 1 : 0\n this.joinPending = true\n this.destroyed = false\n this.joinCallback = function(onDone){ onDone && onDone() }\n this.stopCallback = function(){ }\n this.pendingJoinOps = this.parent ? null : []\n this.viewHooks = {}\n this.uploaders = {}\n this.formSubmits = []\n this.children = this.parent ? null : {}\n this.root.children[this.id] = {}\n this.channel = this.liveSocket.channel(`lv:${this.id}`, () => {\n return {\n redirect: this.redirect ? this.href : undefined,\n url: this.redirect ? undefined : this.href || undefined,\n params: this.connectParams(),\n session: this.getSession(),\n static: this.getStatic(),\n flash: this.flash\n }\n })\n this.showLoader(this.liveSocket.loaderTimeout)\n this.bindChannel()\n }\n\n setHref(href){ this.href = href }\n\n setRedirect(href){\n this.redirect = true\n this.href = href\n }\n\n isMain(){ return this.el.hasAttribute(PHX_MAIN) }\n\n connectParams(){\n let params = this.liveSocket.params(this.el)\n let manifest =\n DOM.all(document, `[${this.binding(PHX_TRACK_STATIC)}]`)\n .map(node => node.src || node.href).filter(url => typeof (url) === \"string\")\n\n if(manifest.length > 0){ params[\"_track_static\"] = manifest }\n params[\"_mounts\"] = this.joinCount\n\n return params\n }\n\n isConnected(){ return this.channel.canPush() }\n\n getSession(){ return this.el.getAttribute(PHX_SESSION) }\n\n getStatic(){\n let val = this.el.getAttribute(PHX_STATIC)\n return val === \"\" ? null : val\n }\n\n destroy(callback = function (){ }){\n this.destroyAllChildren()\n this.destroyed = true\n delete this.root.children[this.id]\n if(this.parent){ delete this.root.children[this.parent.id][this.id] }\n clearTimeout(this.loaderTimer)\n let onFinished = () => {\n callback()\n for(let id in this.viewHooks){\n this.destroyHook(this.viewHooks[id])\n }\n }\n\n DOM.markPhxChildDestroyed(this.el)\n\n this.log(\"destroyed\", () => [\"the child has been removed from the parent\"])\n this.channel.leave()\n .receive(\"ok\", onFinished)\n .receive(\"error\", onFinished)\n .receive(\"timeout\", onFinished)\n }\n\n setContainerClasses(...classes){\n this.el.classList.remove(\n PHX_CONNECTED_CLASS,\n PHX_DISCONNECTED_CLASS,\n PHX_ERROR_CLASS\n )\n this.el.classList.add(...classes)\n }\n\n showLoader(timeout){\n clearTimeout(this.loaderTimer)\n if(timeout){\n this.loaderTimer = setTimeout(() => this.showLoader(), timeout)\n } else {\n for(let id in this.viewHooks){ this.viewHooks[id].__disconnected() }\n this.setContainerClasses(PHX_DISCONNECTED_CLASS)\n }\n }\n\n hideLoader(){\n clearTimeout(this.loaderTimer)\n this.setContainerClasses(PHX_CONNECTED_CLASS)\n }\n\n triggerReconnected(){\n for(let id in this.viewHooks){ this.viewHooks[id].__reconnected() }\n }\n\n log(kind, msgCallback){\n this.liveSocket.log(this, kind, msgCallback)\n }\n\n transition(time, onStart, onDone = function(){}){\n this.liveSocket.transition(time, onStart, onDone)\n }\n\n withinTargets(phxTarget, callback){\n if(phxTarget instanceof HTMLElement || phxTarget instanceof SVGElement){\n return this.liveSocket.owner(phxTarget, view => callback(view, phxTarget))\n }\n\n if(isCid(phxTarget)){\n let targets = DOM.findComponentNodeList(this.el, phxTarget)\n if(targets.length === 0){\n logError(`no component found matching phx-target of ${phxTarget}`)\n } else {\n callback(this, parseInt(phxTarget))\n }\n } else {\n let targets = Array.from(document.querySelectorAll(phxTarget))\n if(targets.length === 0){ logError(`nothing found matching the phx-target selector \"${phxTarget}\"`) }\n targets.forEach(target => this.liveSocket.owner(target, view => callback(view, target)))\n }\n }\n\n applyDiff(type, rawDiff, callback){\n this.log(type, () => [\"\", clone(rawDiff)])\n let {diff, reply, events, title} = Rendered.extract(rawDiff)\n if(title){ DOM.putTitle(title) }\n\n callback({diff, reply, events})\n return reply\n }\n\n onJoin(resp){\n let {rendered, container} = resp\n if(container){\n let [tag, attrs] = container\n this.el = DOM.replaceRootContainer(this.el, tag, attrs)\n }\n this.childJoins = 0\n this.joinPending = true\n this.flash = null\n\n Browser.dropLocal(this.liveSocket.localStorage, window.location.pathname, CONSECUTIVE_RELOADS)\n this.applyDiff(\"mount\", rendered, ({diff, events}) => {\n this.rendered = new Rendered(this.id, diff)\n let html = this.renderContainer(null, \"join\")\n this.dropPendingRefs()\n let forms = this.formsForRecovery(html)\n this.joinCount++\n\n if(forms.length > 0){\n forms.forEach(([form, newForm, newCid], i) => {\n this.pushFormRecovery(form, newCid, resp => {\n if(i === forms.length - 1){\n this.onJoinComplete(resp, html, events)\n }\n })\n })\n } else {\n this.onJoinComplete(resp, html, events)\n }\n })\n }\n\n dropPendingRefs(){\n DOM.all(document, `[${PHX_REF_SRC}=\"${this.id}\"][${PHX_REF}]`, el => {\n el.removeAttribute(PHX_REF)\n el.removeAttribute(PHX_REF_SRC)\n })\n }\n\n onJoinComplete({live_patch}, html, events){\n // In order to provide a better experience, we want to join\n // all LiveViews first and only then apply their patches.\n if(this.joinCount > 1 || (this.parent && !this.parent.isJoinPending())){\n return this.applyJoinPatch(live_patch, html, events)\n }\n\n // One downside of this approach is that we need to find phxChildren\n // in the html fragment, instead of directly on the DOM. The fragment\n // also does not include PHX_STATIC, so we need to copy it over from\n // the DOM.\n let newChildren = DOM.findPhxChildrenInFragment(html, this.id).filter(toEl => {\n let fromEl = toEl.id && this.el.querySelector(`[id=\"${toEl.id}\"]`)\n let phxStatic = fromEl && fromEl.getAttribute(PHX_STATIC)\n if(phxStatic){ toEl.setAttribute(PHX_STATIC, phxStatic) }\n return this.joinChild(toEl)\n })\n\n if(newChildren.length === 0){\n if(this.parent){\n this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, events)])\n this.parent.ackJoin(this)\n } else {\n this.onAllChildJoinsComplete()\n this.applyJoinPatch(live_patch, html, events)\n }\n } else {\n this.root.pendingJoinOps.push([this, () => this.applyJoinPatch(live_patch, html, events)])\n }\n }\n\n attachTrueDocEl(){\n this.el = DOM.byId(this.id)\n this.el.setAttribute(PHX_ROOT_ID, this.root.id)\n }\n\n applyJoinPatch(live_patch, html, events){\n this.attachTrueDocEl()\n let patch = new DOMPatch(this, this.el, this.id, html, null)\n patch.markPrunableContentForRemoval()\n this.performPatch(patch, false)\n this.joinNewChildren()\n DOM.all(this.el, `[${this.binding(PHX_HOOK)}], [data-phx-${PHX_HOOK}]`, hookEl => {\n let hook = this.addHook(hookEl)\n if(hook){ hook.__mounted() }\n })\n\n this.joinPending = false\n this.liveSocket.dispatchEvents(events)\n this.applyPendingUpdates()\n\n if(live_patch){\n let {kind, to} = live_patch\n this.liveSocket.historyPatch(to, kind)\n }\n this.hideLoader()\n if(this.joinCount > 1){ this.triggerReconnected() }\n this.stopCallback()\n }\n\n triggerBeforeUpdateHook(fromEl, toEl){\n this.liveSocket.triggerDOM(\"onBeforeElUpdated\", [fromEl, toEl])\n let hook = this.getHook(fromEl)\n let isIgnored = hook && DOM.isIgnored(fromEl, this.binding(PHX_UPDATE))\n if(hook && !fromEl.isEqualNode(toEl) && !(isIgnored && isEqualObj(fromEl.dataset, toEl.dataset))){\n hook.__beforeUpdate()\n return hook\n }\n }\n\n performPatch(patch, pruneCids){\n let removedEls = []\n let phxChildrenAdded = false\n let updatedHookIds = new Set()\n\n patch.after(\"added\", el => {\n this.liveSocket.triggerDOM(\"onNodeAdded\", [el])\n\n let newHook = this.addHook(el)\n if(newHook){ newHook.__mounted() }\n })\n\n patch.after(\"phxChildAdded\", el => {\n if(DOM.isPhxSticky(el)){\n this.liveSocket.joinRootViews()\n } else {\n phxChildrenAdded = true\n }\n })\n\n patch.before(\"updated\", (fromEl, toEl) => {\n let hook = this.triggerBeforeUpdateHook(fromEl, toEl)\n if(hook){ updatedHookIds.add(fromEl.id) }\n })\n\n patch.after(\"updated\", el => {\n if(updatedHookIds.has(el.id)){ this.getHook(el).__updated() }\n })\n\n patch.after(\"discarded\", (el) => {\n if(el.nodeType === Node.ELEMENT_NODE){ removedEls.push(el) }\n })\n\n patch.after(\"transitionsDiscarded\", els => this.afterElementsRemoved(els, pruneCids))\n patch.perform()\n this.afterElementsRemoved(removedEls, pruneCids)\n\n return phxChildrenAdded\n }\n\n afterElementsRemoved(elements, pruneCids){\n let destroyedCIDs = []\n elements.forEach(parent => {\n let components = DOM.all(parent, `[${PHX_COMPONENT}]`)\n let hooks = DOM.all(parent, `[${this.binding(PHX_HOOK)}]`)\n components.concat(parent).forEach(el => {\n let cid = this.componentID(el)\n if(isCid(cid) && destroyedCIDs.indexOf(cid) === -1){ destroyedCIDs.push(cid) }\n })\n hooks.concat(parent).forEach(hookEl => {\n let hook = this.getHook(hookEl)\n hook && this.destroyHook(hook)\n })\n })\n // We should not pruneCids on joins. Otherwise, in case of\n // rejoins, we may notify cids that no longer belong to the\n // current LiveView to be removed.\n if(pruneCids){\n this.maybePushComponentsDestroyed(destroyedCIDs)\n }\n }\n\n joinNewChildren(){\n DOM.findPhxChildren(this.el, this.id).forEach(el => this.joinChild(el))\n }\n\n getChildById(id){ return this.root.children[this.id][id] }\n\n getDescendentByEl(el){\n if(el.id === this.id){\n return this\n } else {\n return this.children[el.getAttribute(PHX_PARENT_ID)][el.id]\n }\n }\n\n destroyDescendent(id){\n for(let parentId in this.root.children){\n for(let childId in this.root.children[parentId]){\n if(childId === id){ return this.root.children[parentId][childId].destroy() }\n }\n }\n }\n\n joinChild(el){\n let child = this.getChildById(el.id)\n if(!child){\n let view = new View(el, this.liveSocket, this)\n this.root.children[this.id][view.id] = view\n view.join()\n this.childJoins++\n return true\n }\n }\n\n isJoinPending(){ return this.joinPending }\n\n ackJoin(_child){\n this.childJoins--\n\n if(this.childJoins === 0){\n if(this.parent){\n this.parent.ackJoin(this)\n } else {\n this.onAllChildJoinsComplete()\n }\n }\n }\n\n onAllChildJoinsComplete(){\n this.joinCallback(() => {\n this.pendingJoinOps.forEach(([view, op]) => {\n if(!view.isDestroyed()){ op() }\n })\n this.pendingJoinOps = []\n })\n }\n\n update(diff, events){\n if(this.isJoinPending() || (this.liveSocket.hasPendingLink() && !DOM.isPhxSticky(this.el))){\n return this.pendingDiffs.push({diff, events})\n }\n\n this.rendered.mergeDiff(diff)\n let phxChildrenAdded = false\n\n // When the diff only contains component diffs, then walk components\n // and patch only the parent component containers found in the diff.\n // Otherwise, patch entire LV container.\n if(this.rendered.isComponentOnlyDiff(diff)){\n this.liveSocket.time(\"component patch complete\", () => {\n let parentCids = DOM.findParentCIDs(this.el, this.rendered.componentCIDs(diff))\n parentCids.forEach(parentCID => {\n if(this.componentPatch(this.rendered.getComponent(diff, parentCID), parentCID)){ phxChildrenAdded = true }\n })\n })\n } else if(!isEmpty(diff)){\n this.liveSocket.time(\"full patch complete\", () => {\n let html = this.renderContainer(diff, \"update\")\n let patch = new DOMPatch(this, this.el, this.id, html, null)\n phxChildrenAdded = this.performPatch(patch, true)\n })\n }\n\n this.liveSocket.dispatchEvents(events)\n if(phxChildrenAdded){ this.joinNewChildren() }\n }\n\n renderContainer(diff, kind){\n return this.liveSocket.time(`toString diff (${kind})`, () => {\n let tag = this.el.tagName\n // Don't skip any component in the diff nor any marked as pruned\n // (as they may have been added back)\n let cids = diff ? this.rendered.componentCIDs(diff).concat(this.pruningCIDs) : null\n let html = this.rendered.toString(cids)\n return `<${tag}>${html}</${tag}>`\n })\n }\n\n componentPatch(diff, cid){\n if(isEmpty(diff)) return false\n let html = this.rendered.componentToString(cid)\n let patch = new DOMPatch(this, this.el, this.id, html, cid)\n let childrenAdded = this.performPatch(patch, true)\n return childrenAdded\n }\n\n getHook(el){ return this.viewHooks[ViewHook.elementID(el)] }\n\n addHook(el){\n if(ViewHook.elementID(el) || !el.getAttribute){ return }\n let hookName = el.getAttribute(`data-phx-${PHX_HOOK}`) || el.getAttribute(this.binding(PHX_HOOK))\n if(hookName && !this.ownsElement(el)){ return }\n let callbacks = this.liveSocket.getHookCallbacks(hookName)\n\n if(callbacks){\n if(!el.id){ logError(`no DOM ID for hook \"${hookName}\". Hooks require a unique ID on each element.`, el) }\n let hook = new ViewHook(this, el, callbacks)\n this.viewHooks[ViewHook.elementID(hook.el)] = hook\n return hook\n } else if(hookName !== null){\n logError(`unknown hook found for \"${hookName}\"`, el)\n }\n }\n\n destroyHook(hook){\n hook.__destroyed()\n hook.__cleanup__()\n delete this.viewHooks[ViewHook.elementID(hook.el)]\n }\n\n applyPendingUpdates(){\n this.pendingDiffs.forEach(({diff, events}) => this.update(diff, events))\n this.pendingDiffs = []\n }\n\n onChannel(event, cb){\n this.liveSocket.onChannel(this.channel, event, resp => {\n if(this.isJoinPending()){\n this.root.pendingJoinOps.push([this, () => cb(resp)])\n } else {\n this.liveSocket.requestDOMUpdate(() => cb(resp))\n }\n })\n }\n\n bindChannel(){\n // The diff event should be handled by the regular update operations.\n // All other operations are queued to be applied only after join.\n this.liveSocket.onChannel(this.channel, \"diff\", (rawDiff) => {\n this.liveSocket.requestDOMUpdate(() => {\n this.applyDiff(\"update\", rawDiff, ({diff, events}) => this.update(diff, events))\n })\n })\n this.onChannel(\"redirect\", ({to, flash}) => this.onRedirect({to, flash}))\n this.onChannel(\"live_patch\", (redir) => this.onLivePatch(redir))\n this.onChannel(\"live_redirect\", (redir) => this.onLiveRedirect(redir))\n this.channel.onError(reason => this.onError(reason))\n this.channel.onClose(reason => this.onClose(reason))\n }\n\n destroyAllChildren(){\n for(let id in this.root.children[this.id]){\n this.getChildById(id).destroy()\n }\n }\n\n onLiveRedirect(redir){\n let {to, kind, flash} = redir\n let url = this.expandURL(to)\n this.liveSocket.historyRedirect(url, kind, flash)\n }\n\n onLivePatch(redir){\n let {to, kind} = redir\n this.href = this.expandURL(to)\n this.liveSocket.historyPatch(to, kind)\n }\n\n expandURL(to){\n return to.startsWith(\"/\") ? `${window.location.protocol}//${window.location.host}${to}` : to\n }\n\n onRedirect({to, flash}){ this.liveSocket.redirect(to, flash) }\n\n isDestroyed(){ return this.destroyed }\n\n join(callback){\n if(this.isMain()){\n this.stopCallback = this.liveSocket.withPageLoading({to: this.href, kind: \"initial\"})\n }\n this.joinCallback = (onDone) => {\n onDone = onDone || function(){}\n callback ? callback(this.joinCount, onDone) : onDone()\n }\n this.liveSocket.wrapPush(this, {timeout: false}, () => {\n return this.channel.join()\n .receive(\"ok\", data => {\n if(!this.isDestroyed()){\n this.liveSocket.requestDOMUpdate(() => this.onJoin(data))\n }\n })\n .receive(\"error\", resp => !this.isDestroyed() && this.onJoinError(resp))\n .receive(\"timeout\", () => !this.isDestroyed() && this.onJoinError({reason: \"timeout\"}))\n })\n }\n\n onJoinError(resp){\n if(resp.reason === \"unauthorized\" || resp.reason === \"stale\"){\n this.log(\"error\", () => [\"unauthorized live_redirect. Falling back to page request\", resp])\n return this.onRedirect({to: this.href})\n }\n if(resp.redirect || resp.live_redirect){\n this.joinPending = false\n this.channel.leave()\n }\n if(resp.redirect){ return this.onRedirect(resp.redirect) }\n if(resp.live_redirect){ return this.onLiveRedirect(resp.live_redirect) }\n this.log(\"error\", () => [\"unable to join\", resp])\n if(this.liveSocket.isConnected()){ this.liveSocket.reloadWithJitter(this) }\n }\n\n onClose(reason){\n if(this.isDestroyed()){ return }\n if(this.liveSocket.hasPendingLink() && reason !== \"leave\"){\n return this.liveSocket.reloadWithJitter(this)\n }\n this.destroyAllChildren()\n this.liveSocket.dropActiveElement(this)\n // document.activeElement can be null in Internet Explorer 11\n if(document.activeElement){ document.activeElement.blur() }\n if(this.liveSocket.isUnloaded()){\n this.showLoader(BEFORE_UNLOAD_LOADER_TIMEOUT)\n }\n }\n\n onError(reason){\n this.onClose(reason)\n if(this.liveSocket.isConnected()){ this.log(\"error\", () => [\"view crashed\", reason]) }\n if(!this.liveSocket.isUnloaded()){ this.displayError() }\n }\n\n displayError(){\n if(this.isMain()){ DOM.dispatchEvent(window, \"phx:page-loading-start\", {detail: {to: this.href, kind: \"error\"}}) }\n this.showLoader()\n this.setContainerClasses(PHX_DISCONNECTED_CLASS, PHX_ERROR_CLASS)\n }\n\n pushWithReply(refGenerator, event, payload, onReply = function (){ }){\n if(!this.isConnected()){ return }\n\n let [ref, [el], opts] = refGenerator ? refGenerator() : [null, [], {}]\n let onLoadingDone = function(){ }\n if(opts.page_loading || (el && (el.getAttribute(this.binding(PHX_PAGE_LOADING)) !== null))){\n onLoadingDone = this.liveSocket.withPageLoading({kind: \"element\", target: el})\n }\n\n if(typeof (payload.cid) !== \"number\"){ delete payload.cid }\n return (\n this.liveSocket.wrapPush(this, {timeout: true}, () => {\n return this.channel.push(event, payload, PUSH_TIMEOUT).receive(\"ok\", resp => {\n if(ref !== null){ this.undoRefs(ref) }\n let finish = (hookReply) => {\n if(resp.redirect){ this.onRedirect(resp.redirect) }\n if(resp.live_patch){ this.onLivePatch(resp.live_patch) }\n if(resp.live_redirect){ this.onLiveRedirect(resp.live_redirect) }\n onLoadingDone()\n onReply(resp, hookReply)\n }\n if(resp.diff){\n this.liveSocket.requestDOMUpdate(() => {\n let hookReply = this.applyDiff(\"update\", resp.diff, ({diff, events}) => {\n this.update(diff, events)\n })\n finish(hookReply)\n })\n } else {\n finish(null)\n }\n })\n })\n )\n }\n\n undoRefs(ref){\n DOM.all(document, `[${PHX_REF_SRC}=\"${this.id}\"][${PHX_REF}=\"${ref}\"]`, el => {\n let disabledVal = el.getAttribute(PHX_DISABLED)\n // remove refs\n el.removeAttribute(PHX_REF)\n el.removeAttribute(PHX_REF_SRC)\n // restore inputs\n if(el.getAttribute(PHX_READONLY) !== null){\n el.readOnly = false\n el.removeAttribute(PHX_READONLY)\n }\n if(disabledVal !== null){\n el.disabled = disabledVal === \"true\" ? true : false\n el.removeAttribute(PHX_DISABLED)\n }\n // remove classes\n PHX_EVENT_CLASSES.forEach(className => DOM.removeClass(el, className))\n // restore disables\n let disableRestore = el.getAttribute(PHX_DISABLE_WITH_RESTORE)\n if(disableRestore !== null){\n el.innerText = disableRestore\n el.removeAttribute(PHX_DISABLE_WITH_RESTORE)\n }\n let toEl = DOM.private(el, PHX_REF)\n if(toEl){\n let hook = this.triggerBeforeUpdateHook(el, toEl)\n DOMPatch.patchEl(el, toEl, this.liveSocket.getActiveElement())\n if(hook){ hook.__updated() }\n DOM.deletePrivate(el, PHX_REF)\n }\n })\n }\n\n putRef(elements, event, opts = {}){\n let newRef = this.ref++\n let disableWith = this.binding(PHX_DISABLE_WITH)\n if(opts.loading){ elements = elements.concat(DOM.all(document, opts.loading))}\n\n elements.forEach(el => {\n el.classList.add(`phx-${event}-loading`)\n el.setAttribute(PHX_REF, newRef)\n el.setAttribute(PHX_REF_SRC, this.el.id)\n let disableText = el.getAttribute(disableWith)\n if(disableText !== null){\n if(!el.getAttribute(PHX_DISABLE_WITH_RESTORE)){\n el.setAttribute(PHX_DISABLE_WITH_RESTORE, el.innerText)\n }\n if(disableText !== \"\"){ el.innerText = disableText }\n el.setAttribute(\"disabled\", \"\")\n }\n })\n return [newRef, elements, opts]\n }\n\n componentID(el){\n let cid = el.getAttribute && el.getAttribute(PHX_COMPONENT)\n return cid ? parseInt(cid) : null\n }\n\n targetComponentID(target, targetCtx, opts = {}){\n if(isCid(targetCtx)){ return targetCtx }\n\n let cidOrSelector = target.getAttribute(this.binding(\"target\"))\n if(isCid(cidOrSelector)){\n return parseInt(cidOrSelector)\n } else if(targetCtx && (cidOrSelector !== null || opts.target)){\n return this.closestComponentID(targetCtx)\n } else {\n return null\n }\n }\n\n closestComponentID(targetCtx){\n if(isCid(targetCtx)){\n return targetCtx\n } else if(targetCtx){\n return maybe(targetCtx.closest(`[${PHX_COMPONENT}]`), el => this.ownsElement(el) && this.componentID(el))\n } else {\n return null\n }\n }\n\n pushHookEvent(targetCtx, event, payload, onReply){\n if(!this.isConnected()){\n this.log(\"hook\", () => [\"unable to push hook event. LiveView not connected\", event, payload])\n return false\n }\n let [ref, els, opts] = this.putRef([], \"hook\")\n this.pushWithReply(() => [ref, els, opts], \"event\", {\n type: \"hook\",\n event: event,\n value: payload,\n cid: this.closestComponentID(targetCtx)\n }, (resp, reply) => onReply(reply, ref))\n\n return ref\n }\n\n extractMeta(el, meta, value){\n let prefix = this.binding(\"value-\")\n for(let i = 0; i < el.attributes.length; i++){\n if(!meta){ meta = {} }\n let name = el.attributes[i].name\n if(name.startsWith(prefix)){ meta[name.replace(prefix, \"\")] = el.getAttribute(name) }\n }\n if(el.value !== undefined){\n if(!meta){ meta = {} }\n meta.value = el.value\n\n if(el.tagName === \"INPUT\" && CHECKABLE_INPUTS.indexOf(el.type) >= 0 && !el.checked){\n delete meta.value\n }\n }\n if(value){\n if(!meta){ meta = {} }\n for(let key in value){ meta[key] = value[key] }\n }\n return meta\n }\n\n pushEvent(type, el, targetCtx, phxEvent, meta, opts = {}){\n this.pushWithReply(() => this.putRef([el], type, opts), \"event\", {\n type: type,\n event: phxEvent,\n value: this.extractMeta(el, meta, opts.value),\n cid: this.targetComponentID(el, targetCtx, opts)\n })\n }\n\n pushFileProgress(fileEl, entryRef, progress, onReply = function (){ }){\n this.liveSocket.withinOwners(fileEl.form, (view, targetCtx) => {\n view.pushWithReply(null, \"progress\", {\n event: fileEl.getAttribute(view.binding(PHX_PROGRESS)),\n ref: fileEl.getAttribute(PHX_UPLOAD_REF),\n entry_ref: entryRef,\n progress: progress,\n cid: view.targetComponentID(fileEl.form, targetCtx)\n }, onReply)\n })\n }\n\n pushInput(inputEl, targetCtx, forceCid, phxEvent, opts, callback){\n let uploads\n let cid = isCid(forceCid) ? forceCid : this.targetComponentID(inputEl.form, targetCtx)\n let refGenerator = () => this.putRef([inputEl, inputEl.form], \"change\", opts)\n let formData\n if(inputEl.getAttribute(this.binding(\"change\"))){\n formData = serializeForm(inputEl.form, {_target: opts._target}, [inputEl.name])\n } else {\n formData = serializeForm(inputEl.form, {_target: opts._target})\n }\n if(DOM.isUploadInput(inputEl) && inputEl.files && inputEl.files.length > 0){\n LiveUploader.trackFiles(inputEl, Array.from(inputEl.files))\n }\n uploads = LiveUploader.serializeUploads(inputEl)\n let event = {\n type: \"form\",\n event: phxEvent,\n value: formData,\n uploads: uploads,\n cid: cid\n }\n this.pushWithReply(refGenerator, \"event\", event, resp => {\n DOM.showError(inputEl, this.liveSocket.binding(PHX_FEEDBACK_FOR))\n if(DOM.isUploadInput(inputEl) && inputEl.getAttribute(\"data-phx-auto-upload\") !== null){\n if(LiveUploader.filesAwaitingPreflight(inputEl).length > 0){\n let [ref, _els] = refGenerator()\n this.uploadFiles(inputEl.form, targetCtx, ref, cid, (_uploads) => {\n callback && callback(resp)\n this.triggerAwaitingSubmit(inputEl.form)\n })\n }\n } else {\n callback && callback(resp)\n }\n })\n }\n\n triggerAwaitingSubmit(formEl){\n let awaitingSubmit = this.getScheduledSubmit(formEl)\n if(awaitingSubmit){\n let [_el, _ref, _opts, callback] = awaitingSubmit\n this.cancelSubmit(formEl)\n callback()\n }\n }\n\n getScheduledSubmit(formEl){\n return this.formSubmits.find(([el, _ref, _opts, _callback]) => el.isSameNode(formEl))\n }\n\n scheduleSubmit(formEl, ref, opts, callback){\n if(this.getScheduledSubmit(formEl)){ return true }\n this.formSubmits.push([formEl, ref, opts, callback])\n }\n\n cancelSubmit(formEl){\n this.formSubmits = this.formSubmits.filter(([el, ref, _callback]) => {\n if(el.isSameNode(formEl)){\n this.undoRefs(ref)\n return false\n } else {\n return true\n }\n })\n }\n\n pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply){\n let filterIgnored = el => {\n let userIgnored = closestPhxBinding(el, `${this.binding(PHX_UPDATE)}=ignore`, el.form)\n return !(userIgnored || closestPhxBinding(el, \"data-phx-update=ignore\", el.form))\n }\n let filterDisables = el => {\n return el.hasAttribute(this.binding(PHX_DISABLE_WITH))\n }\n let filterButton = el => el.tagName == \"BUTTON\"\n\n let filterInput = el => [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(el.tagName)\n\n let refGenerator = () => {\n let formElements = Array.from(formEl.elements)\n let disables = formElements.filter(filterDisables)\n let buttons = formElements.filter(filterButton).filter(filterIgnored)\n let inputs = formElements.filter(filterInput).filter(filterIgnored)\n\n buttons.forEach(button => {\n button.setAttribute(PHX_DISABLED, button.disabled)\n button.disabled = true\n })\n inputs.forEach(input => {\n input.setAttribute(PHX_READONLY, input.readOnly)\n input.readOnly = true\n if(input.files){\n input.setAttribute(PHX_DISABLED, input.disabled)\n input.disabled = true\n }\n })\n formEl.setAttribute(this.binding(PHX_PAGE_LOADING), \"\")\n return this.putRef([formEl].concat(disables).concat(buttons).concat(inputs), \"submit\", opts)\n }\n\n let cid = this.targetComponentID(formEl, targetCtx)\n if(LiveUploader.hasUploadsInProgress(formEl)){\n let [ref, _els] = refGenerator()\n let push = () => this.pushFormSubmit(formEl, targetCtx, phxEvent, opts, onReply)\n return this.scheduleSubmit(formEl, ref, opts, push)\n } else if(LiveUploader.inputsAwaitingPreflight(formEl).length > 0){\n let [ref, els] = refGenerator()\n let proxyRefGen = () => [ref, els, opts]\n this.uploadFiles(formEl, targetCtx, ref, cid, (_uploads) => {\n let formData = serializeForm(formEl, {})\n this.pushWithReply(proxyRefGen, \"event\", {\n type: \"form\",\n event: phxEvent,\n value: formData,\n cid: cid\n }, onReply)\n })\n } else {\n let formData = serializeForm(formEl, {})\n this.pushWithReply(refGenerator, \"event\", {\n type: \"form\",\n event: phxEvent,\n value: formData,\n cid: cid\n }, onReply)\n }\n }\n\n uploadFiles(formEl, targetCtx, ref, cid, onComplete){\n let joinCountAtUpload = this.joinCount\n let inputEls = LiveUploader.activeFileInputs(formEl)\n let numFileInputsInProgress = inputEls.length\n\n // get each file input\n inputEls.forEach(inputEl => {\n let uploader = new LiveUploader(inputEl, this, () => {\n numFileInputsInProgress--\n if(numFileInputsInProgress === 0){ onComplete() }\n });\n\n this.uploaders[inputEl] = uploader\n let entries = uploader.entries().map(entry => entry.toPreflightPayload())\n\n let payload = {\n ref: inputEl.getAttribute(PHX_UPLOAD_REF),\n entries: entries,\n cid: this.targetComponentID(inputEl.form, targetCtx)\n }\n\n this.log(\"upload\", () => [\"sending preflight request\", payload])\n\n this.pushWithReply(null, \"allow_upload\", payload, resp => {\n this.log(\"upload\", () => [\"got preflight response\", resp])\n if(resp.error){\n this.undoRefs(ref)\n let [entry_ref, reason] = resp.error\n this.log(\"upload\", () => [`error for entry ${entry_ref}`, reason])\n } else {\n let onError = (callback) => {\n this.channel.onError(() => {\n if(this.joinCount === joinCountAtUpload){ callback() }\n })\n }\n uploader.initAdapterUpload(resp, onError, this.liveSocket)\n }\n })\n })\n }\n\n dispatchUploads(name, filesOrBlobs){\n let inputs = DOM.findUploadInputs(this.el).filter(el => el.name === name)\n if(inputs.length === 0){ logError(`no live file inputs found matching the name \"${name}\"`) }\n else if(inputs.length > 1){ logError(`duplicate live file inputs found matching the name \"${name}\"`) }\n else { DOM.dispatchEvent(inputs[0], PHX_TRACK_UPLOADS, {detail: {files: filesOrBlobs}}) }\n }\n\n pushFormRecovery(form, newCid, callback){\n this.liveSocket.withinOwners(form, (view, targetCtx) => {\n let input = form.elements[0]\n let phxEvent = form.getAttribute(this.binding(PHX_AUTO_RECOVER)) || form.getAttribute(this.binding(\"change\"))\n\n JS.exec(\"change\", phxEvent, view, input, [\"push\", {_target: input.name, newCid: newCid, callback: callback}])\n })\n }\n\n pushLinkPatch(href, targetEl, callback){\n let linkRef = this.liveSocket.setPendingLink(href)\n let refGen = targetEl ? () => this.putRef([targetEl], \"click\") : null\n let fallback = () => this.liveSocket.redirect(window.location.href)\n\n let push = this.pushWithReply(refGen, \"live_patch\", {url: href}, resp => {\n this.liveSocket.requestDOMUpdate(() => {\n if(resp.link_redirect){\n this.liveSocket.replaceMain(href, null, callback, linkRef)\n } else {\n if(this.liveSocket.commitPendingLink(linkRef)){\n this.href = href\n }\n this.applyPendingUpdates()\n callback && callback(linkRef)\n }\n })\n })\n\n if(push){\n push.receive(\"timeout\", fallback)\n } else {\n fallback()\n }\n }\n\n formsForRecovery(html){\n if(this.joinCount === 0){ return [] }\n\n let phxChange = this.binding(\"change\")\n let template = document.createElement(\"template\")\n template.innerHTML = html\n\n return (\n DOM.all(this.el, `form[${phxChange}]`)\n .filter(form => form.id && this.ownsElement(form))\n .filter(form => form.elements.length > 0)\n .filter(form => form.getAttribute(this.binding(PHX_AUTO_RECOVER)) !== \"ignore\")\n .map(form => {\n let newForm = template.content.querySelector(`form[id=\"${form.id}\"][${phxChange}=\"${form.getAttribute(phxChange)}\"]`)\n if(newForm){\n return [form, newForm, this.targetComponentID(newForm)]\n } else {\n return [form, null, null]\n }\n })\n .filter(([form, newForm, newCid]) => newForm)\n )\n }\n\n maybePushComponentsDestroyed(destroyedCIDs){\n let willDestroyCIDs = destroyedCIDs.filter(cid => {\n return DOM.findComponentNodeList(this.el, cid).length === 0\n })\n if(willDestroyCIDs.length > 0){\n this.pruningCIDs.push(...willDestroyCIDs)\n\n this.pushWithReply(null, \"cids_will_destroy\", {cids: willDestroyCIDs}, () => {\n // The cids are either back on the page or they will be fully removed,\n // so we can remove them from the pruningCIDs.\n this.pruningCIDs = this.pruningCIDs.filter(cid => willDestroyCIDs.indexOf(cid) !== -1)\n\n // See if any of the cids we wanted to destroy were added back,\n // if they were added back, we don't actually destroy them.\n let completelyDestroyCIDs = willDestroyCIDs.filter(cid => {\n return DOM.findComponentNodeList(this.el, cid).length === 0\n })\n\n if(completelyDestroyCIDs.length > 0){\n this.pushWithReply(null, \"cids_destroyed\", {cids: completelyDestroyCIDs}, (resp) => {\n this.rendered.pruneCIDs(resp.cids)\n })\n }\n })\n }\n }\n\n ownsElement(el){\n return el.getAttribute(PHX_PARENT_ID) === this.id ||\n maybe(el.closest(PHX_VIEW_SELECTOR), node => node.id) === this.id\n }\n\n submitForm(form, targetCtx, phxEvent, opts = {}){\n DOM.putPrivate(form, PHX_HAS_SUBMITTED, true)\n let phxFeedback = this.liveSocket.binding(PHX_FEEDBACK_FOR)\n let inputs = Array.from(form.elements)\n this.liveSocket.blurActiveElement(this)\n this.pushFormSubmit(form, targetCtx, phxEvent, opts, () => {\n inputs.forEach(input => DOM.showError(input, phxFeedback))\n this.liveSocket.restorePreviouslyActiveFocus()\n })\n }\n\n binding(kind){ return this.liveSocket.binding(kind) }\n}\n", "/** Initializes the LiveSocket\n *\n *\n * @param {string} endPoint - The string WebSocket endpoint, ie, `\"wss://example.com/live\"`,\n * `\"/live\"` (inherited host & protocol)\n * @param {Phoenix.Socket} socket - the required Phoenix Socket class imported from \"phoenix\". For example:\n *\n * import {Socket} from \"phoenix\"\n * import {LiveSocket} from \"phoenix_live_view\"\n * let liveSocket = new LiveSocket(\"/live\", Socket, {...})\n *\n * @param {Object} [opts] - Optional configuration. Outside of keys listed below, all\n * configuration is passed directly to the Phoenix Socket constructor.\n * @param {Object} [opts.defaults] - The optional defaults to use for various bindings,\n * such as `phx-debounce`. Supports the following keys:\n *\n * - debounce - the millisecond phx-debounce time. Defaults 300\n * - throttle - the millisecond phx-throttle time. Defaults 300\n *\n * @param {Function} [opts.params] - The optional function for passing connect params.\n * The function receives the element associated with a given LiveView. For example:\n *\n * (el) => {view: el.getAttribute(\"data-my-view-name\", token: window.myToken}\n *\n * @param {string} [opts.bindingPrefix] - The optional prefix to use for all phx DOM annotations.\n * Defaults to \"phx-\".\n * @param {Object} [opts.hooks] - The optional object for referencing LiveView hook callbacks.\n * @param {Object} [opts.uploaders] - The optional object for referencing LiveView uploader callbacks.\n * @param {integer} [opts.loaderTimeout] - The optional delay in milliseconds to wait before apply\n * loading states.\n * @param {integer} [opts.maxReloads] - The maximum reloads before entering failsafe mode.\n * @param {integer} [opts.reloadJitterMin] - The minimum time between normal reload attempts.\n * @param {integer} [opts.reloadJitterMax] - The maximum time between normal reload attempts.\n * @param {integer} [opts.failsafeJitter] - The time between reload attempts in failsafe mode.\n * @param {Function} [opts.viewLogger] - The optional function to log debug information. For example:\n *\n * (view, kind, msg, obj) => console.log(`${view.id} ${kind}: ${msg} - `, obj)\n *\n * @param {Object} [opts.metadata] - The optional object mapping event names to functions for\n * populating event metadata. For example:\n *\n * metadata: {\n * click: (e, el) => {\n * return {\n * ctrlKey: e.ctrlKey,\n * metaKey: e.metaKey,\n * detail: e.detail || 1,\n * }\n * },\n * keydown: (e, el) => {\n * return {\n * key: e.key,\n * ctrlKey: e.ctrlKey,\n * metaKey: e.metaKey,\n * shiftKey: e.shiftKey\n * }\n * }\n * }\n * @param {Object} [opts.sessionStorage] - An optional Storage compatible object\n * Useful when LiveView won't have access to `sessionStorage`. For example, This could\n * happen if a site loads a cross-domain LiveView in an iframe. Example usage:\n *\n * class InMemoryStorage {\n * constructor() { this.storage = {} }\n * getItem(keyName) { return this.storage[keyName] }\n * removeItem(keyName) { delete this.storage[keyName] }\n * setItem(keyName, keyValue) { this.storage[keyName] = keyValue }\n * }\n *\n * @param {Object} [opts.localStorage] - An optional Storage compatible object\n * Useful for when LiveView won't have access to `localStorage`.\n * See `opts.sessionStorage` for examples.\n*/\n\nimport {\n BINDING_PREFIX,\n CONSECUTIVE_RELOADS,\n DEFAULTS,\n FAILSAFE_JITTER,\n LOADER_TIMEOUT,\n MAX_RELOADS,\n PHX_DEBOUNCE,\n PHX_DROP_TARGET,\n PHX_HAS_FOCUSED,\n PHX_KEY,\n PHX_LINK_STATE,\n PHX_LIVE_LINK,\n PHX_LV_DEBUG,\n PHX_LV_LATENCY_SIM,\n PHX_LV_PROFILE,\n PHX_MAIN,\n PHX_PARENT_ID,\n PHX_VIEW_SELECTOR,\n PHX_ROOT_ID,\n PHX_THROTTLE,\n PHX_TRACK_UPLOADS,\n PHX_SESSION,\n RELOAD_JITTER_MIN,\n RELOAD_JITTER_MAX,\n} from \"./constants\"\n\nimport {\n clone,\n closestPhxBinding,\n closure,\n debug,\n isObject,\n maybe\n} from \"./utils\"\n\nimport Browser from \"./browser\"\nimport DOM from \"./dom\"\nimport Hooks from \"./hooks\"\nimport LiveUploader from \"./live_uploader\"\nimport View from \"./view\"\nimport JS from \"./js\"\n\nexport default class LiveSocket {\n constructor(url, phxSocket, opts = {}){\n this.unloaded = false\n if(!phxSocket || phxSocket.constructor.name === \"Object\"){\n throw new Error(`\n a phoenix Socket must be provided as the second argument to the LiveSocket constructor. For example:\n\n import {Socket} from \"phoenix\"\n import {LiveSocket} from \"phoenix_live_view\"\n let liveSocket = new LiveSocket(\"/live\", Socket, {...})\n `)\n }\n this.socket = new phxSocket(url, opts)\n this.bindingPrefix = opts.bindingPrefix || BINDING_PREFIX\n this.opts = opts\n this.params = closure(opts.params || {})\n this.viewLogger = opts.viewLogger\n this.metadataCallbacks = opts.metadata || {}\n this.defaults = Object.assign(clone(DEFAULTS), opts.defaults || {})\n this.activeElement = null\n this.prevActive = null\n this.silenced = false\n this.main = null\n this.outgoingMainEl = null\n this.clickStartedAtTarget = null\n this.linkRef = 1\n this.roots = {}\n this.href = window.location.href\n this.pendingLink = null\n this.currentLocation = clone(window.location)\n this.hooks = opts.hooks || {}\n this.uploaders = opts.uploaders || {}\n this.loaderTimeout = opts.loaderTimeout || LOADER_TIMEOUT\n this.reloadWithJitterTimer = null\n this.maxReloads = opts.maxReloads || MAX_RELOADS\n this.reloadJitterMin = opts.reloadJitterMin || RELOAD_JITTER_MIN\n this.reloadJitterMax = opts.reloadJitterMax || RELOAD_JITTER_MAX\n this.failsafeJitter = opts.failsafeJitter || FAILSAFE_JITTER\n this.localStorage = opts.localStorage || window.localStorage\n this.sessionStorage = opts.sessionStorage || window.sessionStorage\n this.boundTopLevelEvents = false\n this.domCallbacks = Object.assign({onNodeAdded: closure(), onBeforeElUpdated: closure()}, opts.dom || {})\n this.transitions = new TransitionSet()\n window.addEventListener(\"pagehide\", _e => {\n this.unloaded = true\n })\n this.socket.onOpen(() => {\n if(this.isUnloaded()){\n // reload page if being restored from back/forward cache and browser does not emit \"pageshow\"\n window.location.reload()\n }\n })\n }\n\n // public\n\n isProfileEnabled(){ return this.sessionStorage.getItem(PHX_LV_PROFILE) === \"true\" }\n\n isDebugEnabled(){ return this.sessionStorage.getItem(PHX_LV_DEBUG) === \"true\" }\n\n isDebugDisabled(){ return this.sessionStorage.getItem(PHX_LV_DEBUG) === \"false\" }\n\n enableDebug(){ this.sessionStorage.setItem(PHX_LV_DEBUG, \"true\") }\n\n enableProfiling(){ this.sessionStorage.setItem(PHX_LV_PROFILE, \"true\") }\n\n disableDebug(){ this.sessionStorage.setItem(PHX_LV_DEBUG, \"false\") }\n\n disableProfiling(){ this.sessionStorage.removeItem(PHX_LV_PROFILE) }\n\n enableLatencySim(upperBoundMs){\n this.enableDebug()\n console.log(\"latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable\")\n this.sessionStorage.setItem(PHX_LV_LATENCY_SIM, upperBoundMs)\n }\n\n disableLatencySim(){ this.sessionStorage.removeItem(PHX_LV_LATENCY_SIM) }\n\n getLatencySim(){\n let str = this.sessionStorage.getItem(PHX_LV_LATENCY_SIM)\n return str ? parseInt(str) : null\n }\n\n getSocket(){ return this.socket }\n\n connect(){\n // enable debug by default if on localhost and not explicitly disabled\n if(window.location.hostname === \"localhost\" && !this.isDebugDisabled()){ this.enableDebug() }\n let doConnect = () => {\n if(this.joinRootViews()){\n this.bindTopLevelEvents()\n this.socket.connect()\n } else if(this.main){\n this.socket.connect()\n }\n }\n if([\"complete\", \"loaded\", \"interactive\"].indexOf(document.readyState) >= 0){\n doConnect()\n } else {\n document.addEventListener(\"DOMContentLoaded\", () => doConnect())\n }\n }\n\n disconnect(callback){\n clearTimeout(this.reloadWithJitterTimer)\n this.socket.disconnect(callback)\n }\n\n replaceTransport(transport){\n clearTimeout(this.reloadWithJitterTimer)\n this.socket.replaceTransport(transport)\n this.connect()\n }\n\n execJS(el, encodedJS, eventType = null){\n this.owner(el, view => JS.exec(eventType, encodedJS, view, el))\n }\n\n // private\n\n triggerDOM(kind, args){ this.domCallbacks[kind](...args) }\n\n time(name, func){\n if(!this.isProfileEnabled() || !console.time){ return func() }\n console.time(name)\n let result = func()\n console.timeEnd(name)\n return result\n }\n\n log(view, kind, msgCallback){\n if(this.viewLogger){\n let [msg, obj] = msgCallback()\n this.viewLogger(view, kind, msg, obj)\n } else if(this.isDebugEnabled()){\n let [msg, obj] = msgCallback()\n debug(view, kind, msg, obj)\n }\n }\n\n requestDOMUpdate(callback){\n this.transitions.after(callback)\n }\n\n transition(time, onStart, onDone = function(){}){\n this.transitions.addTransition(time, onStart, onDone)\n }\n\n onChannel(channel, event, cb){\n channel.on(event, data => {\n let latency = this.getLatencySim()\n if(!latency){\n cb(data)\n } else {\n console.log(`simulating ${latency}ms of latency from server to client`)\n setTimeout(() => cb(data), latency)\n }\n })\n }\n\n wrapPush(view, opts, push){\n let latency = this.getLatencySim()\n let oldJoinCount = view.joinCount\n if(!latency){\n if(this.isConnected() && opts.timeout){\n return push().receive(\"timeout\", () => {\n if(view.joinCount === oldJoinCount && !view.isDestroyed()){\n this.reloadWithJitter(view, () => {\n this.log(view, \"timeout\", () => [\"received timeout while communicating with server. Falling back to hard refresh for recovery\"])\n })\n }\n })\n } else {\n return push()\n }\n }\n\n console.log(`simulating ${latency}ms of latency from client to server`)\n let fakePush = {\n receives: [],\n receive(kind, cb){ this.receives.push([kind, cb]) }\n }\n setTimeout(() => {\n if(view.isDestroyed()){ return }\n fakePush.receives.reduce((acc, [kind, cb]) => acc.receive(kind, cb), push())\n }, latency)\n return fakePush\n }\n\n reloadWithJitter(view, log){\n clearTimeout(this.reloadWithJitterTimer)\n this.disconnect()\n let minMs = this.reloadJitterMin\n let maxMs = this.reloadJitterMax\n let afterMs = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs\n let tries = Browser.updateLocal(this.localStorage, window.location.pathname, CONSECUTIVE_RELOADS, 0, count => count + 1)\n if(tries > this.maxReloads){\n afterMs = this.failsafeJitter\n }\n this.reloadWithJitterTimer = setTimeout(() => {\n // if view has recovered, such as transport replaced, then cancel\n if(view.isDestroyed() || view.isConnected()){ return }\n view.destroy()\n log ? log() : this.log(view, \"join\", () => [`encountered ${tries} consecutive reloads`])\n if(tries > this.maxReloads){\n this.log(view, \"join\", () => [`exceeded ${this.maxReloads} consecutive reloads. Entering failsafe mode`])\n }\n if(this.hasPendingLink()){\n window.location = this.pendingLink\n } else {\n window.location.reload()\n }\n }, afterMs)\n }\n\n getHookCallbacks(name){\n return name && name.startsWith(\"Phoenix.\") ? Hooks[name.split(\".\")[1]] : this.hooks[name]\n }\n\n isUnloaded(){ return this.unloaded }\n\n isConnected(){ return this.socket.isConnected() }\n\n getBindingPrefix(){ return this.bindingPrefix }\n\n binding(kind){ return `${this.getBindingPrefix()}${kind}` }\n\n channel(topic, params){ return this.socket.channel(topic, params) }\n\n joinRootViews(){\n let rootsFound = false\n DOM.all(document, `${PHX_VIEW_SELECTOR}:not([${PHX_PARENT_ID}])`, rootEl => {\n if(!this.getRootById(rootEl.id)){\n let view = this.newRootView(rootEl)\n view.setHref(this.getHref())\n view.join()\n if(rootEl.hasAttribute(PHX_MAIN)){ this.main = view }\n }\n rootsFound = true\n })\n return rootsFound\n }\n\n redirect(to, flash){\n this.disconnect()\n Browser.redirect(to, flash)\n }\n\n replaceMain(href, flash, callback = null, linkRef = this.setPendingLink(href)){\n this.outgoingMainEl = this.outgoingMainEl || this.main.el\n let newMainEl = DOM.cloneNode(this.outgoingMainEl, \"\")\n this.main.showLoader(this.loaderTimeout)\n this.main.destroy()\n\n this.main = this.newRootView(newMainEl, flash)\n this.main.setRedirect(href)\n this.transitionRemoves()\n this.main.join((joinCount, onDone) => {\n if(joinCount === 1 && this.commitPendingLink(linkRef)){\n this.requestDOMUpdate(() => {\n DOM.findPhxSticky(document).forEach(el => newMainEl.appendChild(el))\n this.outgoingMainEl.replaceWith(newMainEl)\n this.outgoingMainEl = null\n callback && requestAnimationFrame(callback)\n onDone()\n })\n }\n })\n }\n\n transitionRemoves(elements){\n let removeAttr = this.binding(\"remove\")\n elements = elements || DOM.all(document, `[${removeAttr}]`)\n elements.forEach(el => {\n if(document.body.contains(el)){ // skip children already removed\n this.execJS(el, el.getAttribute(removeAttr), \"remove\")\n }\n })\n }\n\n isPhxView(el){ return el.getAttribute && el.getAttribute(PHX_SESSION) !== null }\n\n newRootView(el, flash){\n let view = new View(el, this, null, flash)\n this.roots[view.id] = view\n return view\n }\n\n owner(childEl, callback){\n let view = maybe(childEl.closest(PHX_VIEW_SELECTOR), el => this.getViewByEl(el)) || this.main\n if(view){ callback(view) }\n }\n\n withinOwners(childEl, callback){\n this.owner(childEl, view => callback(view, childEl))\n }\n\n getViewByEl(el){\n let rootId = el.getAttribute(PHX_ROOT_ID)\n return maybe(this.getRootById(rootId), root => root.getDescendentByEl(el))\n }\n\n getRootById(id){ return this.roots[id] }\n\n destroyAllViews(){\n for(let id in this.roots){\n this.roots[id].destroy()\n delete this.roots[id]\n }\n this.main = null\n }\n\n destroyViewByEl(el){\n let root = this.getRootById(el.getAttribute(PHX_ROOT_ID))\n if(root && root.id === el.id){\n root.destroy()\n delete this.roots[root.id]\n } else if(root){\n root.destroyDescendent(el.id)\n }\n }\n\n setActiveElement(target){\n if(this.activeElement === target){ return }\n this.activeElement = target\n let cancel = () => {\n if(target === this.activeElement){ this.activeElement = null }\n target.removeEventListener(\"mouseup\", this)\n target.removeEventListener(\"touchend\", this)\n }\n target.addEventListener(\"mouseup\", cancel)\n target.addEventListener(\"touchend\", cancel)\n }\n\n getActiveElement(){\n if(document.activeElement === document.body){\n return this.activeElement || document.activeElement\n } else {\n // document.activeElement can be null in Internet Explorer 11\n return document.activeElement || document.body\n }\n }\n\n dropActiveElement(view){\n if(this.prevActive && view.ownsElement(this.prevActive)){\n this.prevActive = null\n }\n }\n\n restorePreviouslyActiveFocus(){\n if(this.prevActive && this.prevActive !== document.body){\n this.prevActive.focus()\n }\n }\n\n blurActiveElement(){\n this.prevActive = this.getActiveElement()\n if(this.prevActive !== document.body){ this.prevActive.blur() }\n }\n\n bindTopLevelEvents(){\n if(this.boundTopLevelEvents){ return }\n\n this.boundTopLevelEvents = true\n // enter failsafe reload if server has gone away intentionally, such as \"disconnect\" broadcast\n this.socket.onClose(event => {\n if(event && event.code === 1000 && this.main){\n this.reloadWithJitter(this.main)\n }\n })\n document.body.addEventListener(\"click\", function (){ }) // ensure all click events bubble for mobile Safari\n window.addEventListener(\"pageshow\", e => {\n if(e.persisted){ // reload page if being restored from back/forward cache\n this.getSocket().disconnect()\n this.withPageLoading({to: window.location.href, kind: \"redirect\"})\n window.location.reload()\n }\n }, true)\n this.bindNav()\n this.bindClicks()\n this.bindForms()\n this.bind({keyup: \"keyup\", keydown: \"keydown\"}, (e, type, view, targetEl, phxEvent, eventTarget) => {\n let matchKey = targetEl.getAttribute(this.binding(PHX_KEY))\n let pressedKey = e.key && e.key.toLowerCase() // chrome clicked autocompletes send a keydown without key\n if(matchKey && matchKey.toLowerCase() !== pressedKey){ return }\n\n let data = {key: e.key, ...this.eventMeta(type, e, targetEl)}\n JS.exec(type, phxEvent, view, targetEl, [\"push\", {data}])\n })\n this.bind({blur: \"focusout\", focus: \"focusin\"}, (e, type, view, targetEl, phxEvent, eventTarget) => {\n if(!eventTarget){\n let data = {key: e.key, ...this.eventMeta(type, e, targetEl)}\n JS.exec(type, phxEvent, view, targetEl, [\"push\", {data}])\n }\n })\n this.bind({blur: \"blur\", focus: \"focus\"}, (e, type, view, targetEl, targetCtx, phxEvent, phxTarget) => {\n // blur and focus are triggered on document and window. Discard one to avoid dups\n if(phxTarget === \"window\"){\n let data = this.eventMeta(type, e, targetEl)\n JS.exec(type, phxEvent, view, targetEl, [\"push\", {data}])\n }\n })\n window.addEventListener(\"dragover\", e => e.preventDefault())\n window.addEventListener(\"drop\", e => {\n e.preventDefault()\n let dropTargetId = maybe(closestPhxBinding(e.target, this.binding(PHX_DROP_TARGET)), trueTarget => {\n return trueTarget.getAttribute(this.binding(PHX_DROP_TARGET))\n })\n let dropTarget = dropTargetId && document.getElementById(dropTargetId)\n let files = Array.from(e.dataTransfer.files || [])\n if(!dropTarget || dropTarget.disabled || files.length === 0 || !(dropTarget.files instanceof FileList)){ return }\n\n LiveUploader.trackFiles(dropTarget, files)\n dropTarget.dispatchEvent(new Event(\"input\", {bubbles: true}))\n })\n this.on(PHX_TRACK_UPLOADS, e => {\n let uploadTarget = e.target\n if(!DOM.isUploadInput(uploadTarget)){ return }\n let files = Array.from(e.detail.files || []).filter(f => f instanceof File || f instanceof Blob)\n LiveUploader.trackFiles(uploadTarget, files)\n uploadTarget.dispatchEvent(new Event(\"input\", {bubbles: true}))\n })\n }\n\n eventMeta(eventName, e, targetEl){\n let callback = this.metadataCallbacks[eventName]\n return callback ? callback(e, targetEl) : {}\n }\n\n setPendingLink(href){\n this.linkRef++\n this.pendingLink = href\n return this.linkRef\n }\n\n commitPendingLink(linkRef){\n if(this.linkRef !== linkRef){\n return false\n } else {\n this.href = this.pendingLink\n this.pendingLink = null\n return true\n }\n }\n\n getHref(){ return this.href }\n\n hasPendingLink(){ return !!this.pendingLink }\n\n bind(events, callback){\n for(let event in events){\n let browserEventName = events[event]\n\n this.on(browserEventName, e => {\n let binding = this.binding(event)\n let windowBinding = this.binding(`window-${event}`)\n let targetPhxEvent = e.target.getAttribute && e.target.getAttribute(binding)\n if(targetPhxEvent){\n this.debounce(e.target, e, browserEventName, () => {\n this.withinOwners(e.target, view => {\n callback(e, event, view, e.target, targetPhxEvent, null)\n })\n })\n } else {\n DOM.all(document, `[${windowBinding}]`, el => {\n let phxEvent = el.getAttribute(windowBinding)\n this.debounce(el, e, browserEventName, () => {\n this.withinOwners(el, view => {\n callback(e, event, view, el, phxEvent, \"window\")\n })\n })\n })\n }\n })\n }\n }\n\n bindClicks(){\n window.addEventListener(\"mousedown\", e => this.clickStartedAtTarget = e.target)\n this.bindClick(\"click\", \"click\", false)\n this.bindClick(\"mousedown\", \"capture-click\", true)\n }\n\n bindClick(eventName, bindingName, capture){\n let click = this.binding(bindingName)\n window.addEventListener(eventName, e => {\n let target = null\n if(capture){\n target = e.target.matches(`[${click}]`) ? e.target : e.target.querySelector(`[${click}]`)\n } else {\n let clickStartedAtTarget = this.clickStartedAtTarget || e.target\n target = closestPhxBinding(clickStartedAtTarget, click)\n this.dispatchClickAway(e, clickStartedAtTarget)\n this.clickStartedAtTarget = null\n }\n let phxEvent = target && target.getAttribute(click)\n if(!phxEvent){ return }\n if(target.getAttribute(\"href\") === \"#\"){ e.preventDefault() }\n\n this.debounce(target, e, \"click\", () => {\n this.withinOwners(target, view => {\n JS.exec(\"click\", phxEvent, view, target, [\"push\", {data: this.eventMeta(\"click\", e, target)}])\n })\n })\n }, capture)\n }\n\n dispatchClickAway(e, clickStartedAt){\n let phxClickAway = this.binding(\"click-away\")\n DOM.all(document, `[${phxClickAway}]`, el => {\n if(!(el.isSameNode(clickStartedAt) || el.contains(clickStartedAt))){\n this.withinOwners(e.target, view => {\n let phxEvent = el.getAttribute(phxClickAway)\n if(JS.isVisible(el)){\n JS.exec(\"click\", phxEvent, view, el, [\"push\", {data: this.eventMeta(\"click\", e, e.target)}])\n }\n })\n }\n })\n }\n\n bindNav(){\n if(!Browser.canPushState()){ return }\n if(history.scrollRestoration){ history.scrollRestoration = \"manual\" }\n let scrollTimer = null\n window.addEventListener(\"scroll\", _e => {\n clearTimeout(scrollTimer)\n scrollTimer = setTimeout(() => {\n Browser.updateCurrentState(state => Object.assign(state, {scroll: window.scrollY}))\n }, 100)\n })\n window.addEventListener(\"popstate\", event => {\n if(!this.registerNewLocation(window.location)){ return }\n let {type, id, root, scroll} = event.state || {}\n let href = window.location.href\n\n this.requestDOMUpdate(() => {\n if(this.main.isConnected() && (type === \"patch\" && id === this.main.id)){\n this.main.pushLinkPatch(href, null)\n } else {\n this.replaceMain(href, null, () => {\n if(root){ this.replaceRootHistory() }\n if(typeof(scroll) === \"number\"){\n setTimeout(() => {\n window.scrollTo(0, scroll)\n }, 0) // the body needs to render before we scroll.\n }\n })\n }\n })\n }, false)\n window.addEventListener(\"click\", e => {\n let target = closestPhxBinding(e.target, PHX_LIVE_LINK)\n let type = target && target.getAttribute(PHX_LIVE_LINK)\n let wantsNewTab = e.metaKey || e.ctrlKey || e.button === 1\n if(!type || !this.isConnected() || !this.main || wantsNewTab){ return }\n\n let href = target.href\n let linkState = target.getAttribute(PHX_LINK_STATE)\n e.preventDefault()\n e.stopImmediatePropagation() // do not bubble click to regular phx-click bindings\n if(this.pendingLink === href){ return }\n\n this.requestDOMUpdate(() => {\n if(type === \"patch\"){\n this.pushHistoryPatch(href, linkState, target)\n } else if(type === \"redirect\"){\n this.historyRedirect(href, linkState)\n } else {\n throw new Error(`expected ${PHX_LIVE_LINK} to be \"patch\" or \"redirect\", got: ${type}`)\n }\n })\n }, false)\n }\n\n dispatchEvent(event, payload = {}){\n DOM.dispatchEvent(window, `phx:${event}`, {detail: payload})\n }\n\n dispatchEvents(events){\n events.forEach(([event, payload]) => this.dispatchEvent(event, payload))\n }\n\n withPageLoading(info, callback){\n DOM.dispatchEvent(window, \"phx:page-loading-start\", {detail: info})\n let done = () => DOM.dispatchEvent(window, \"phx:page-loading-stop\", {detail: info})\n return callback ? callback(done) : done\n }\n\n pushHistoryPatch(href, linkState, targetEl){\n this.withPageLoading({to: href, kind: \"patch\"}, done => {\n this.main.pushLinkPatch(href, targetEl, linkRef => {\n this.historyPatch(href, linkState, linkRef)\n done()\n })\n })\n }\n\n historyPatch(href, linkState, linkRef = this.setPendingLink(href)){\n if(!this.commitPendingLink(linkRef)){ return }\n\n Browser.pushState(linkState, {type: \"patch\", id: this.main.id}, href)\n this.registerNewLocation(window.location)\n }\n\n historyRedirect(href, linkState, flash){\n let scroll = window.scrollY\n this.withPageLoading({to: href, kind: \"redirect\"}, done => {\n this.replaceMain(href, flash, () => {\n Browser.pushState(linkState, {type: \"redirect\", id: this.main.id, scroll: scroll}, href)\n this.registerNewLocation(window.location)\n done()\n })\n })\n }\n\n replaceRootHistory(){\n Browser.pushState(\"replace\", {root: true, type: \"patch\", id: this.main.id})\n }\n\n registerNewLocation(newLocation){\n let {pathname, search} = this.currentLocation\n if(pathname + search === newLocation.pathname + newLocation.search){\n return false\n } else {\n this.currentLocation = clone(newLocation)\n return true\n }\n }\n\n bindForms(){\n let iterations = 0\n this.on(\"submit\", e => {\n let phxEvent = e.target.getAttribute(this.binding(\"submit\"))\n if(!phxEvent){ return }\n e.preventDefault()\n e.target.disabled = true\n this.withinOwners(e.target, view => {\n JS.exec(\"submit\", phxEvent, view, e.target, [\"push\", {}])\n })\n }, false)\n\n for(let type of [\"change\", \"input\"]){\n this.on(type, e => {\n let phxChange = this.binding(\"change\")\n let input = e.target\n let inputEvent = input.getAttribute(phxChange)\n let formEvent = input.form && input.form.getAttribute(phxChange)\n let phxEvent = inputEvent || formEvent\n if(!phxEvent){ return }\n if(input.type === \"number\" && input.validity && input.validity.badInput){ return }\n\n let dispatcher = inputEvent ? input : input.form\n let currentIterations = iterations\n iterations++\n let {at: at, type: lastType} = DOM.private(input, \"prev-iteration\") || {}\n // detect dup because some browsers dispatch both \"input\" and \"change\"\n if(at === currentIterations - 1 && type !== lastType){ return }\n\n DOM.putPrivate(input, \"prev-iteration\", {at: currentIterations, type: type})\n\n this.debounce(input, e, type, () => {\n this.withinOwners(dispatcher, view => {\n DOM.putPrivate(input, PHX_HAS_FOCUSED, true)\n if(!DOM.isTextualInput(input)){\n this.setActiveElement(input)\n }\n JS.exec(\"change\", phxEvent, view, input, [\"push\", {_target: e.target.name, dispatcher: dispatcher}])\n })\n })\n }, false)\n }\n }\n\n debounce(el, event, eventType, callback){\n if(eventType === \"blur\" || eventType === \"focusout\"){ return callback() }\n\n let phxDebounce = this.binding(PHX_DEBOUNCE)\n let phxThrottle = this.binding(PHX_THROTTLE)\n let defaultDebounce = this.defaults.debounce.toString()\n let defaultThrottle = this.defaults.throttle.toString()\n\n this.withinOwners(el, view => {\n let asyncFilter = () => !view.isDestroyed() && document.body.contains(el)\n DOM.debounce(el, event, phxDebounce, defaultDebounce, phxThrottle, defaultThrottle, asyncFilter, () => {\n callback()\n })\n })\n }\n\n silenceEvents(callback){\n this.silenced = true\n callback()\n this.silenced = false\n }\n\n on(event, callback){\n window.addEventListener(event, e => {\n if(!this.silenced){ callback(e) }\n })\n }\n}\n\nclass TransitionSet {\n constructor(){\n this.transitions = new Set()\n this.pendingOps = []\n this.reset()\n }\n\n reset(){\n this.transitions.forEach(timer => {\n cancelTimeout(timer)\n this.transitions.delete(timer)\n })\n this.flushPendingOps()\n }\n\n after(callback){\n if(this.size() === 0){\n callback()\n } else {\n this.pushPendingOp(callback)\n }\n }\n\n addTransition(time, onStart, onDone){\n onStart()\n let timer = setTimeout(() => {\n this.transitions.delete(timer)\n onDone()\n if(this.size() === 0){ this.flushPendingOps() }\n }, time)\n this.transitions.add(timer)\n }\n\n pushPendingOp(op){ this.pendingOps.push(op) }\n\n size(){ return this.transitions.size }\n\n flushPendingOps(){\n this.pendingOps.forEach(op => op())\n this.pendingOps = []\n }\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;AAAA;AAAA;AAAA;;;ACCO,IAAM,sBAAsB;AAC5B,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAAA,EAC/B;AAAA,EAAqB;AAAA,EAAsB;AAAA,EAC3C;AAAA,EAAuB;AAAA,EAAqB;AAAA,EAAoB;AAAA;AAE3D,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;AACvB,IAAM,UAAU;AAChB,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AACvB,IAAM,uBAAuB;AAC7B,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAC9B,IAAM,wBAAwB;AAC9B,IAAM,WAAW;AACjB,IAAM,YAAY;AAClB,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAC9B,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AACtB,IAAM,WAAW;AACjB,IAAM,cAAc;AACpB,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB,CAAC,QAAQ,YAAY,UAAU,SAAS,YAAY,UAAU,OAAO,OAAO,QAAQ,QAAQ,kBAAkB,SAAS;AAChJ,IAAM,mBAAmB,CAAC,YAAY;AACtC,IAAM,oBAAoB;AAC1B,IAAM,cAAc;AACpB,IAAM,oBAAoB,IAAI;AAC9B,IAAM,aAAa;AACnB,IAAM,aAAa;AACnB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,mBAAmB;AACzB,IAAM,2BAA2B;AACjC,IAAM,WAAW;AACjB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,aAAa;AACnB,IAAM,UAAU;AAChB,IAAM,cAAc;AACpB,IAAM,mBAAmB;AACzB,IAAM,eAAe;AACrB,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;AAC3B,IAAM,eAAe;AACrB,IAAM,iBAAiB;AACvB,IAAM,+BAA+B;AACrC,IAAM,iBAAiB;AACvB,IAAM,eAAe;AAGrB,IAAM,mBAAmB;AACzB,IAAM,YAAY;AAClB,IAAM,oBAAoB;AAC1B,IAAM,WAAW;AAAA,EACtB,UAAU;AAAA,EACV,UAAU;AAAA;AAIL,IAAM,WAAW;AACjB,IAAM,SAAS;AACf,IAAM,aAAa;AACnB,IAAM,SAAS;AACf,IAAM,QAAQ;AACd,IAAM,QAAQ;AACd,IAAM,YAAY;;;AC3EzB,0BAAmC;AAAA,EACjC,YAAY,OAAO,WAAW,YAAW;AACvC,SAAK,aAAa;AAClB,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,gBAAgB,WAAW,QAAQ,OAAO,MAAM,OAAO,EAAC,OAAO,MAAM;AAAA;AAAA,EAG5E,MAAM,QAAO;AACX,iBAAa,KAAK;AAClB,SAAK,cAAc;AACnB,SAAK,MAAM,MAAM;AAAA;AAAA,EAGnB,SAAQ;AACN,SAAK,cAAc,QAAQ,YAAU,KAAK,MAAM;AAChD,SAAK,cAAc,OAChB,QAAQ,MAAM,WAAS,KAAK,iBAC5B,QAAQ,SAAS,YAAU,KAAK,MAAM;AAAA;AAAA,EAG3C,SAAQ;AAAE,WAAO,KAAK,UAAU,KAAK,MAAM,KAAK;AAAA;AAAA,EAEhD,gBAAe;AACb,QAAI,SAAS,IAAI,OAAO;AACxB,QAAI,OAAO,KAAK,MAAM,KAAK,MAAM,KAAK,QAAQ,KAAK,YAAY,KAAK;AACpE,WAAO,SAAS,CAAC,MAAM;AACrB,UAAG,EAAE,OAAO,UAAU,MAAK;AACzB,aAAK,UAAU,EAAE,OAAO,OAAO;AAC/B,aAAK,UAAU,EAAE,OAAO;AAAA,aACnB;AACL,eAAO,SAAS,iBAAiB,EAAE,OAAO;AAAA;AAAA;AAG9C,WAAO,kBAAkB;AAAA;AAAA,EAG3B,UAAU,OAAM;AACd,QAAG,CAAC,KAAK,cAAc,YAAW;AAAE;AAAA;AACpC,SAAK,cAAc,KAAK,SAAS,OAC9B,QAAQ,MAAM,MAAM;AACnB,WAAK,MAAM,SAAU,KAAK,SAAS,KAAK,MAAM,KAAK,OAAQ;AAC3D,UAAG,CAAC,KAAK,UAAS;AAChB,aAAK,aAAa,WAAW,MAAM,KAAK,iBAAiB,KAAK,WAAW,mBAAmB;AAAA;AAAA;AAAA;AAAA;;;AC3C/F,IAAI,WAAW,CAAC,KAAK,QAAQ,QAAQ,SAAS,QAAQ,MAAM,KAAK;AAEjE,IAAI,QAAQ,CAAC,QAAQ;AAC1B,MAAI,OAAO,OAAO;AAClB,SAAO,SAAS,YAAa,SAAS,YAAY,iBAAiB,KAAK;AAAA;AAGnE,8BAA6B;AAClC,MAAI,MAAM,IAAI;AACd,MAAI,QAAQ,SAAS,iBAAiB;AACtC,WAAQ,IAAI,GAAG,MAAM,MAAM,QAAQ,IAAI,KAAK,KAAI;AAC9C,QAAG,IAAI,IAAI,MAAM,GAAG,KAAI;AACtB,cAAQ,MAAM,0BAA0B,MAAM,GAAG;AAAA,WAC5C;AACL,UAAI,IAAI,MAAM,GAAG;AAAA;AAAA;AAAA;AAKhB,IAAI,QAAQ,CAAC,MAAM,MAAM,KAAK,QAAQ;AAC3C,MAAG,KAAK,WAAW,kBAAiB;AAClC,YAAQ,IAAI,GAAG,KAAK,MAAM,SAAS,UAAU;AAAA;AAAA;AAK1C,IAAI,UAAU,CAAC,QAAQ,OAAO,QAAQ,aAAa,MAAM,WAAW;AAAE,SAAO;AAAA;AAE7E,IAAI,QAAQ,CAAC,QAAQ;AAAE,SAAO,KAAK,MAAM,KAAK,UAAU;AAAA;AAExD,IAAI,oBAAoB,CAAC,IAAI,SAAS,aAAa;AACxD,KAAG;AACD,QAAG,GAAG,QAAQ,IAAI,aAAY;AAAE,aAAO;AAAA;AACvC,SAAK,GAAG,iBAAiB,GAAG;AAAA,WACtB,OAAO,QAAQ,GAAG,aAAa,KAAK,CAAG,aAAY,SAAS,WAAW,OAAQ,GAAG,QAAQ;AAClG,SAAO;AAAA;AAGF,IAAI,WAAW,CAAC,QAAQ;AAC7B,SAAO,QAAQ,QAAQ,OAAO,QAAQ,YAAY,CAAE,gBAAe;AAAA;AAG9D,IAAI,aAAa,CAAC,MAAM,SAAS,KAAK,UAAU,UAAU,KAAK,UAAU;AAEzE,IAAI,UAAU,CAAC,QAAQ;AAC5B,WAAQ,KAAK,KAAI;AAAE,WAAO;AAAA;AAC1B,SAAO;AAAA;AAGF,IAAI,QAAQ,CAAC,IAAI,aAAa,MAAM,SAAS;AAE7C,IAAI,kBAAkB,SAAU,SAAS,SAAS,MAAM,YAAW;AACxE,UAAQ,QAAQ,WAAS;AACvB,QAAI,gBAAgB,IAAI,cAAc,OAAO,KAAK,OAAO,YAAY;AACrE,kBAAc;AAAA;AAAA;;;AC5DlB,IAAI,UAAU;AAAA,EACZ,eAAc;AAAE,WAAQ,OAAQ,QAAQ,cAAe;AAAA;AAAA,EAEvD,UAAU,cAAc,WAAW,QAAO;AACxC,WAAO,aAAa,WAAW,KAAK,SAAS,WAAW;AAAA;AAAA,EAG1D,YAAY,cAAc,WAAW,QAAQ,SAAS,MAAK;AACzD,QAAI,UAAU,KAAK,SAAS,cAAc,WAAW;AACrD,QAAI,MAAM,KAAK,SAAS,WAAW;AACnC,QAAI,SAAS,YAAY,OAAO,UAAU,KAAK;AAC/C,iBAAa,QAAQ,KAAK,KAAK,UAAU;AACzC,WAAO;AAAA;AAAA,EAGT,SAAS,cAAc,WAAW,QAAO;AACvC,WAAO,KAAK,MAAM,aAAa,QAAQ,KAAK,SAAS,WAAW;AAAA;AAAA,EAGlE,mBAAmB,UAAS;AAC1B,QAAG,CAAC,KAAK,gBAAe;AAAE;AAAA;AAC1B,YAAQ,aAAa,SAAS,QAAQ,SAAS,KAAK,IAAI,OAAO,SAAS;AAAA;AAAA,EAG1E,UAAU,MAAM,MAAM,IAAG;AACvB,QAAG,KAAK,gBAAe;AACrB,UAAG,OAAO,OAAO,SAAS,MAAK;AAC7B,YAAG,KAAK,QAAQ,cAAc,KAAK,QAAO;AAExC,cAAI,eAAe,QAAQ,SAAS;AACpC,uBAAa,SAAS,KAAK;AAC3B,kBAAQ,aAAa,cAAc,IAAI,OAAO,SAAS;AAAA;AAGzD,eAAO,KAAK;AACZ,gBAAQ,OAAO,SAAS,MAAM,IAAI,MAAM;AACxC,YAAI,SAAS,KAAK,gBAAgB,OAAO,SAAS;AAElD,YAAG,QAAO;AACR,iBAAO;AAAA,mBACC,KAAK,SAAS,YAAW;AACjC,iBAAO,OAAO,GAAG;AAAA;AAAA;AAAA,WAGhB;AACL,WAAK,SAAS;AAAA;AAAA;AAAA,EAIlB,UAAU,MAAM,OAAM;AACpB,aAAS,SAAS,GAAG,QAAQ;AAAA;AAAA,EAG/B,UAAU,MAAK;AACb,WAAO,SAAS,OAAO,QAAQ,IAAI,OAAO,iBAAkB,8BAAiC;AAAA;AAAA,EAG/F,SAAS,OAAO,OAAM;AACpB,QAAG,OAAM;AAAE,cAAQ,UAAU,qBAAqB,QAAQ;AAAA;AAC1D,WAAO,WAAW;AAAA;AAAA,EAGpB,SAAS,WAAW,QAAO;AAAE,WAAO,GAAG,aAAa;AAAA;AAAA,EAEpD,gBAAgB,WAAU;AACxB,QAAI,OAAO,UAAU,WAAW,UAAU;AAC1C,QAAG,SAAS,IAAG;AAAE;AAAA;AACjB,WAAO,SAAS,eAAe,SAAS,SAAS,cAAc,WAAW;AAAA;AAAA;AAI9E,IAAO,kBAAQ;;;AC3Cf,IAAI,MAAM;AAAA,EACR,KAAK,IAAG;AAAE,WAAO,SAAS,eAAe,OAAO,SAAS,mBAAmB;AAAA;AAAA,EAE5E,YAAY,IAAI,WAAU;AACxB,OAAG,UAAU,OAAO;AACpB,QAAG,GAAG,UAAU,WAAW,GAAE;AAAE,SAAG,gBAAgB;AAAA;AAAA;AAAA,EAGpD,IAAI,MAAM,OAAO,UAAS;AACxB,QAAG,CAAC,MAAK;AAAE,aAAO;AAAA;AAClB,QAAI,QAAQ,MAAM,KAAK,KAAK,iBAAiB;AAC7C,WAAO,WAAW,MAAM,QAAQ,YAAY;AAAA;AAAA,EAG9C,gBAAgB,MAAK;AACnB,QAAI,WAAW,SAAS,cAAc;AACtC,aAAS,YAAY;AACrB,WAAO,SAAS,QAAQ;AAAA;AAAA,EAG1B,cAAc,IAAG;AAAE,WAAO,GAAG,SAAS,UAAU,GAAG,aAAa,oBAAoB;AAAA;AAAA,EAEpF,iBAAiB,MAAK;AAAE,WAAO,KAAK,IAAI,MAAM,sBAAsB;AAAA;AAAA,EAEpE,sBAAsB,MAAM,KAAI;AAC9B,WAAO,KAAK,yBAAyB,KAAK,IAAI,MAAM,IAAI,kBAAkB,UAAU;AAAA;AAAA,EAGtF,eAAe,MAAK;AAClB,WAAO,KAAK,MAAM,IAAI,QAAQ,MAAM,eAAe,OAAO;AAAA;AAAA,EAG5D,sBAAsB,IAAG;AACvB,QAAG,KAAK,WAAW,KAAI;AAAE,SAAG,aAAa,aAAa;AAAA;AACtD,SAAK,WAAW,IAAI,aAAa;AAAA;AAAA,EAGnC,0BAA0B,MAAM,UAAS;AACvC,QAAI,WAAW,SAAS,cAAc;AACtC,aAAS,YAAY;AACrB,WAAO,KAAK,gBAAgB,SAAS,SAAS;AAAA;AAAA,EAGhD,UAAU,IAAI,WAAU;AACtB,WAAQ,IAAG,aAAa,cAAc,GAAG,aAAa,wBAAwB;AAAA;AAAA,EAGhF,YAAY,IAAI,WAAW,aAAY;AACrC,WAAO,GAAG,gBAAgB,YAAY,QAAQ,GAAG,aAAa,eAAe;AAAA;AAAA,EAG/E,cAAc,IAAG;AAAE,WAAO,KAAK,IAAI,IAAI,IAAI;AAAA;AAAA,EAE3C,gBAAgB,IAAI,UAAS;AAC3B,WAAO,KAAK,IAAI,IAAI,GAAG,qBAAqB,kBAAkB;AAAA;AAAA,EAGhE,eAAe,MAAM,MAAK;AACxB,QAAI,UAAU,IAAI,IAAI;AACtB,WAAO,KAAK,OAAO,CAAC,KAAK,QAAQ;AAC/B,UAAI,WAAW,IAAI,kBAAkB,UAAU;AAE/C,WAAK,yBAAyB,KAAK,IAAI,MAAM,WAAW,MACrD,IAAI,QAAM,SAAS,GAAG,aAAa,iBACnC,QAAQ,cAAY,IAAI,OAAO;AAElC,aAAO;AAAA,OACN;AAAA;AAAA,EAGL,yBAAyB,OAAO,QAAO;AACrC,QAAG,OAAO,cAAc,oBAAmB;AACzC,aAAO,MAAM,OAAO,QAAM,KAAK,mBAAmB,IAAI;AAAA,WACjD;AACL,aAAO;AAAA;AAAA;AAAA,EAIX,mBAAmB,MAAM,QAAO;AAC9B,WAAM,OAAO,KAAK,YAAW;AAC3B,UAAG,KAAK,WAAW,SAAQ;AAAE,eAAO;AAAA;AACpC,UAAG,KAAK,aAAa,iBAAiB,MAAK;AAAE,eAAO;AAAA;AAAA;AAAA;AAAA,EAIxD,QAAQ,IAAI,KAAI;AAAE,WAAO,GAAG,gBAAgB,GAAG,aAAa;AAAA;AAAA,EAE5D,cAAc,IAAI,KAAI;AAAE,OAAG,gBAAgB,OAAQ,GAAG,aAAa;AAAA;AAAA,EAEnE,WAAW,IAAI,KAAK,OAAM;AACxB,QAAG,CAAC,GAAG,cAAa;AAAE,SAAG,eAAe;AAAA;AACxC,OAAG,aAAa,OAAO;AAAA;AAAA,EAGzB,cAAc,IAAI,KAAK,YAAY,YAAW;AAC5C,QAAI,WAAW,KAAK,QAAQ,IAAI;AAChC,QAAG,aAAa,QAAU;AACxB,WAAK,WAAW,IAAI,KAAK,WAAW;AAAA,WAC/B;AACL,WAAK,WAAW,IAAI,KAAK,WAAW;AAAA;AAAA;AAAA,EAIxC,aAAa,QAAQ,QAAO;AAC1B,QAAG,OAAO,cAAa;AACrB,aAAO,eAAe,OAAO;AAAA;AAAA;AAAA,EAIjC,SAAS,KAAI;AACX,QAAI,UAAU,SAAS,cAAc;AACrC,QAAI,EAAC,QAAQ,WAAU,QAAQ;AAC/B,aAAS,QAAQ,GAAG,UAAU,KAAK,MAAM,UAAU;AAAA;AAAA,EAGrD,SAAS,IAAI,OAAO,aAAa,iBAAiB,aAAa,iBAAiB,aAAa,UAAS;AACpG,QAAI,WAAW,GAAG,aAAa;AAC/B,QAAI,WAAW,GAAG,aAAa;AAC/B,QAAG,aAAa,IAAG;AAAE,iBAAW;AAAA;AAChC,QAAG,aAAa,IAAG;AAAE,iBAAW;AAAA;AAChC,QAAI,QAAQ,YAAY;AACxB,YAAO;AAAA,WACA;AAAM,eAAO;AAAA,WAEb;AACH,YAAG,KAAK,KAAK,IAAI,kBAAiB;AAChC,aAAG,iBAAiB,QAAQ,MAAM;AAAA;AAEpC;AAAA;AAGA,YAAI,UAAU,SAAS;AACvB,YAAI,UAAU,MAAM,WAAW,KAAK,cAAc,IAAI,aAAa;AACnE,YAAI,eAAe,KAAK,SAAS,IAAI,kBAAkB;AACvD,YAAG,MAAM,UAAS;AAAE,iBAAO,SAAS,oCAAoC;AAAA;AACxE,YAAG,UAAS;AACV,cAAI,aAAa;AACjB,cAAG,MAAM,SAAS,WAAU;AAC1B,gBAAI,UAAU,KAAK,QAAQ,IAAI;AAC/B,iBAAK,WAAW,IAAI,mBAAmB,MAAM;AAC7C,yBAAa,YAAY,MAAM;AAAA;AAGjC,cAAG,CAAC,cAAc,KAAK,QAAQ,IAAI,YAAW;AAC5C,mBAAO;AAAA,iBACF;AACL;AACA,iBAAK,WAAW,IAAI,WAAW;AAC/B,uBAAW,MAAM;AACf,kBAAG,eAAc;AAAE,qBAAK,aAAa,IAAI;AAAA;AAAA,eACxC;AAAA;AAAA,eAEA;AACL,qBAAW,MAAM;AACf,gBAAG,eAAc;AAAE,mBAAK,aAAa,IAAI,kBAAkB;AAAA;AAAA,aAC1D;AAAA;AAGL,YAAI,OAAO,GAAG;AACd,YAAG,QAAQ,KAAK,KAAK,MAAM,kBAAiB;AAC1C,eAAK,iBAAiB,UAAU,MAAM;AACpC,kBAAM,KAAM,IAAI,SAAS,MAAO,WAAW,CAAC,CAAC,UAAU;AACrD,kBAAI,QAAQ,KAAK,cAAc,UAAU;AACzC,mBAAK,SAAS,OAAO;AACrB,mBAAK,cAAc,OAAO;AAAA;AAAA;AAAA;AAIhC,YAAG,KAAK,KAAK,IAAI,kBAAiB;AAChC,aAAG,iBAAiB,QAAQ,MAAM,KAAK,aAAa,IAAI;AAAA;AAAA;AAAA;AAAA,EAKhE,aAAa,IAAI,KAAK,cAAa;AACjC,QAAI,CAAC,OAAO,WAAW,KAAK,QAAQ,IAAI;AACxC,QAAG,CAAC,cAAa;AAAE,qBAAe;AAAA;AAClC,QAAG,iBAAiB,OAAM;AACxB,WAAK,SAAS,IAAI;AAClB;AAAA;AAAA;AAAA,EAIJ,KAAK,IAAI,KAAI;AACX,QAAG,KAAK,QAAQ,IAAI,SAAS,MAAK;AAAE,aAAO;AAAA;AAC3C,SAAK,WAAW,IAAI,KAAK;AACzB,WAAO;AAAA;AAAA,EAGT,SAAS,IAAI,KAAK,UAAU,WAAW;AAAA,KAAI;AACzC,QAAI,CAAC,gBAAgB,KAAK,QAAQ,IAAI,QAAQ,CAAC,GAAG;AAClD;AACA,SAAK,WAAW,IAAI,KAAK,CAAC,cAAc;AACxC,WAAO;AAAA;AAAA,EAGT,aAAa,WAAW,IAAI,gBAAe;AACzC,QAAI,QAAQ,GAAG,gBAAgB,GAAG,aAAa;AAE/C,QAAI,QAAQ,SAAS,UAAU,cAAc,QAAQ,mBAAmB;AACxE,QAAG,CAAC,OAAM;AAAE;AAAA;AAEZ,QAAG,CAAE,MAAK,QAAQ,OAAO,oBAAoB,KAAK,QAAQ,MAAM,MAAM,qBAAoB;AACxF,SAAG,UAAU,IAAI;AAAA;AAAA;AAAA,EAIrB,UAAU,SAAS,gBAAe;AAChC,QAAG,QAAQ,MAAM,QAAQ,MAAK;AAC5B,WAAK,IAAI,QAAQ,MAAM,IAAI,mBAAmB,QAAQ,UAAU,mBAAmB,QAAQ,UAAU,CAAC,OAAO;AAC3G,aAAK,YAAY,IAAI;AAAA;AAAA;AAAA;AAAA,EAK3B,WAAW,MAAK;AACd,WAAO,KAAK,gBAAgB,KAAK,aAAa;AAAA;AAAA,EAGhD,YAAY,MAAK;AACf,WAAO,KAAK,gBAAgB,KAAK,aAAa,gBAAgB;AAAA;AAAA,EAGhE,cAAc,IAAG;AACf,WAAO,KAAK,WAAW,MAAM,KAAK,KAAK,IAAI,IAAI,IAAI,kBAAkB;AAAA;AAAA,EAGvE,cAAc,QAAQ,MAAM,OAAO,IAAG;AACpC,QAAI,UAAU,KAAK,YAAY,SAAY,OAAO,CAAC,CAAC,KAAK;AACzD,QAAI,YAAY,EAAC,SAAkB,YAAY,MAAM,QAAQ,KAAK,UAAU;AAC5E,QAAI,QAAQ,SAAS,UAAU,IAAI,WAAW,SAAS,aAAa,IAAI,YAAY,MAAM;AAC1F,WAAO,cAAc;AAAA;AAAA,EAGvB,UAAU,MAAM,MAAK;AACnB,QAAG,OAAQ,SAAU,aAAY;AAC/B,aAAO,KAAK,UAAU;AAAA,WACjB;AACL,UAAI,SAAS,KAAK,UAAU;AAC5B,aAAO,YAAY;AACnB,aAAO;AAAA;AAAA;AAAA,EAIX,WAAW,QAAQ,QAAQ,OAAO,IAAG;AACnC,QAAI,UAAU,KAAK,WAAW;AAC9B,QAAI,YAAY,KAAK;AACrB,QAAI,cAAc,OAAO;AACzB,aAAQ,IAAI,YAAY,SAAS,GAAG,KAAK,GAAG,KAAI;AAC9C,UAAI,OAAO,YAAY,GAAG;AAC1B,UAAG,QAAQ,QAAQ,QAAQ,GAAE;AAAE,eAAO,aAAa,MAAM,OAAO,aAAa;AAAA;AAAA;AAG/E,QAAI,cAAc,OAAO;AACzB,aAAQ,IAAI,YAAY,SAAS,GAAG,KAAK,GAAG,KAAI;AAC9C,UAAI,OAAO,YAAY,GAAG;AAC1B,UAAG,WAAU;AACX,YAAG,KAAK,WAAW,YAAY,CAAC,OAAO,aAAa,OAAM;AAAE,iBAAO,gBAAgB;AAAA;AAAA,aAC9E;AACL,YAAG,CAAC,OAAO,aAAa,OAAM;AAAE,iBAAO,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7D,kBAAkB,QAAQ,QAAO;AAE/B,QAAG,CAAE,mBAAkB,oBAAmB;AAAE,UAAI,WAAW,QAAQ,QAAQ,EAAC,SAAS,CAAC;AAAA;AACtF,QAAG,OAAO,UAAS;AACjB,aAAO,aAAa,YAAY;AAAA,WAC3B;AACL,aAAO,gBAAgB;AAAA;AAAA;AAAA,EAI3B,kBAAkB,IAAG;AACnB,WAAO,GAAG,qBAAsB,IAAG,SAAS,UAAU,GAAG,SAAS;AAAA;AAAA,EAGpE,aAAa,SAAS,gBAAgB,cAAa;AACjD,QAAG,CAAC,IAAI,eAAe,UAAS;AAAE;AAAA;AAClC,QAAI,aAAa,QAAQ,QAAQ;AACjC,QAAG,QAAQ,UAAS;AAAE,cAAQ;AAAA;AAC9B,QAAG,CAAC,YAAW;AAAE,cAAQ;AAAA;AACzB,QAAG,KAAK,kBAAkB,UAAS;AACjC,cAAQ,kBAAkB,gBAAgB;AAAA;AAAA;AAAA,EAI9C,YAAY,IAAG;AAAE,WAAO,+BAA+B,KAAK,GAAG,YAAY,GAAG,SAAS;AAAA;AAAA,EAEvF,iBAAiB,IAAG;AAClB,QAAG,cAAc,oBAAoB,iBAAiB,QAAQ,GAAG,KAAK,wBAAwB,GAAE;AAC9F,SAAG,UAAU,GAAG,aAAa,eAAe;AAAA;AAAA;AAAA,EAIhD,eAAe,IAAG;AAAE,WAAO,iBAAiB,QAAQ,GAAG,SAAS;AAAA;AAAA,EAEhE,yBAAyB,IAAI,oBAAmB;AAC9C,WAAO,GAAG,gBAAgB,GAAG,aAAa,wBAAwB;AAAA;AAAA,EAGpE,eAAe,QAAQ,MAAM,aAAY;AACvC,QAAI,MAAM,OAAO,aAAa;AAC9B,QAAG,QAAQ,MAAK;AAAE,aAAO;AAAA;AACzB,QAAI,SAAS,OAAO,aAAa;AAEjC,QAAG,IAAI,YAAY,WAAW,OAAO,aAAa,iBAAiB,MAAK;AACtE,UAAG,IAAI,cAAc,SAAQ;AAAE,YAAI,WAAW,QAAQ,MAAM,EAAC,WAAW;AAAA;AACxE,UAAI,WAAW,QAAQ,SAAS;AAChC,aAAO;AAAA,WACF;AACL,wBAAkB,QAAQ,eAAa;AACrC,eAAO,UAAU,SAAS,cAAc,KAAK,UAAU,IAAI;AAAA;AAE7D,WAAK,aAAa,SAAS;AAC3B,WAAK,aAAa,aAAa;AAC/B,aAAO;AAAA;AAAA;AAAA,EAIX,gBAAgB,WAAW,WAAU;AACnC,QAAG,IAAI,YAAY,WAAW,WAAW,CAAC,UAAU,aAAY;AAC9D,UAAI,WAAW;AACf,gBAAU,WAAW,QAAQ,eAAa;AACxC,YAAG,CAAC,UAAU,IAAG;AAEf,cAAI,kBAAkB,UAAU,aAAa,KAAK,aAAa,UAAU,UAAU,WAAW;AAC9F,cAAG,CAAC,iBAAgB;AAClB,qBAAS;AAAA;AAAA,0BACqB,WAAU,aAAa,UAAU,WAAW;AAAA;AAAA;AAAA;AAE5E,mBAAS,KAAK;AAAA;AAAA;AAGlB,eAAS,QAAQ,eAAa,UAAU;AAAA;AAAA;AAAA,EAI5C,qBAAqB,WAAW,SAAS,OAAM;AAC7C,QAAI,gBAAgB,IAAI,IAAI,CAAC,MAAM,aAAa,YAAY,UAAU;AACtE,QAAG,UAAU,QAAQ,kBAAkB,QAAQ,eAAc;AAC3D,YAAM,KAAK,UAAU,YAClB,OAAO,UAAQ,CAAC,cAAc,IAAI,KAAK,KAAK,gBAC5C,QAAQ,UAAQ,UAAU,gBAAgB,KAAK;AAElD,aAAO,KAAK,OACT,OAAO,UAAQ,CAAC,cAAc,IAAI,KAAK,gBACvC,QAAQ,UAAQ,UAAU,aAAa,MAAM,MAAM;AAEtD,aAAO;AAAA,WAEF;AACL,UAAI,eAAe,SAAS,cAAc;AAC1C,aAAO,KAAK,OAAO,QAAQ,UAAQ,aAAa,aAAa,MAAM,MAAM;AACzE,oBAAc,QAAQ,UAAQ,aAAa,aAAa,MAAM,UAAU,aAAa;AACrF,mBAAa,YAAY,UAAU;AACnC,gBAAU,YAAY;AACtB,aAAO;AAAA;AAAA;AAAA,EAIX,UAAU,IAAI,MAAM,YAAW;AAC7B,QAAI,KAAM,KAAI,QAAQ,IAAI,aAAa,IAAI,KAAK,CAAC,CAAC,kBAAoB,SAAS;AAC/E,QAAG,IAAG;AACJ,UAAI,CAAC,OAAO,KAAK,iBAAiB;AAClC,aAAO;AAAA,WACF;AACL,aAAO,OAAO,eAAgB,aAAa,eAAe;AAAA;AAAA;AAAA,EAI9D,aAAa,IAAI,MAAK;AACpB,SAAK,cAAc,IAAI,UAAU,IAAI,SAAO;AAC1C,aAAO,IAAI,OAAO,CAAC,CAAC,cAAc,OAAO,iBAAiB;AAAA;AAAA;AAAA,EAI9D,UAAU,IAAI,MAAM,IAAG;AACrB,QAAI,gBAAgB,GAAG;AACvB,SAAK,cAAc,IAAI,UAAU,IAAI,SAAO;AAC1C,UAAI,gBAAgB,IAAI,UAAU,CAAC,CAAC,kBAAoB,SAAS;AACjE,UAAG,iBAAiB,GAAE;AACpB,YAAI,iBAAiB,CAAC,MAAM,IAAI;AAAA,aAC3B;AACL,YAAI,KAAK,CAAC,MAAM,IAAI;AAAA;AAEtB,aAAO;AAAA;AAAA;AAAA,EAIX,sBAAsB,IAAG;AACvB,QAAI,MAAM,IAAI,QAAQ,IAAI;AAC1B,QAAG,CAAC,KAAI;AAAE;AAAA;AAEV,QAAI,QAAQ,CAAC,CAAC,MAAM,IAAI,cAAc,KAAK,UAAU,IAAI,MAAM;AAAA;AAAA;AAInE,IAAO,cAAQ;;;AC9Zf,wBAAiC;AAAA,SACxB,SAAS,QAAQ,MAAK;AAC3B,QAAI,QAAQ,KAAK,YAAY;AAC7B,QAAI,aAAa,OAAO,aAAa,uBAAuB,MAAM;AAClE,QAAI,WAAW,WAAW,QAAQ,aAAa,WAAW,UAAU;AACpE,WAAO,KAAK,OAAO,KAAM,UAAS;AAAA;AAAA,SAG7B,cAAc,QAAQ,MAAK;AAChC,QAAI,kBAAkB,OAAO,aAAa,sBAAsB,MAAM;AACtE,QAAI,gBAAgB,gBAAgB,QAAQ,aAAa,WAAW,UAAU;AAC9E,WAAO,iBAAiB,KAAK,SAAS,QAAQ;AAAA;AAAA,EAGhD,YAAY,QAAQ,MAAM,MAAK;AAC7B,SAAK,MAAM,aAAa,WAAW;AACnC,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,eAAe;AACpB,SAAK,UAAU;AACf,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,UAAU,WAAW;AAAA;AAC1B,SAAK,eAAe,KAAK,YAAY,KAAK;AAC1C,SAAK,OAAO,iBAAiB,uBAAuB,KAAK;AAAA;AAAA,EAG3D,WAAU;AAAE,WAAO,KAAK;AAAA;AAAA,EAExB,SAAS,UAAS;AAChB,SAAK,YAAY,KAAK,MAAM;AAC5B,QAAG,KAAK,YAAY,KAAK,mBAAkB;AACzC,UAAG,KAAK,aAAa,KAAI;AACvB,aAAK,YAAY;AACjB,aAAK,oBAAoB;AACzB,aAAK,UAAU;AACf,aAAK,KAAK,iBAAiB,KAAK,QAAQ,KAAK,KAAK,KAAK,MAAM;AAC3D,uBAAa,YAAY,KAAK,QAAQ,KAAK;AAC3C,eAAK;AAAA;AAAA,aAEF;AACL,aAAK,oBAAoB,KAAK;AAC9B,aAAK,KAAK,iBAAiB,KAAK,QAAQ,KAAK,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,EAK7D,SAAQ;AACN,SAAK,eAAe;AACpB,SAAK,UAAU;AACf,SAAK;AAAA;AAAA,EAGP,SAAQ;AAAE,WAAO,KAAK;AAAA;AAAA,EAEtB,MAAM,SAAS,UAAS;AACtB,SAAK,KAAK,iBAAiB,KAAK,QAAQ,KAAK,KAAK,EAAC,OAAO;AAC1D,iBAAa,WAAW,KAAK;AAAA;AAAA,EAK/B,OAAO,UAAS;AACd,SAAK,UAAU,MAAM;AACnB,WAAK,OAAO,oBAAoB,uBAAuB,KAAK;AAC5D;AAAA;AAAA;AAAA,EAIJ,cAAa;AACX,QAAI,aAAa,KAAK,OAAO,aAAa,uBAAuB,MAAM;AACvE,QAAG,WAAW,QAAQ,KAAK,SAAS,IAAG;AAAE,WAAK;AAAA;AAAA;AAAA,EAGhD,qBAAoB;AAClB,WAAO;AAAA,MACL,eAAe,KAAK,KAAK;AAAA,MACzB,MAAM,KAAK,KAAK;AAAA,MAChB,MAAM,KAAK,KAAK;AAAA,MAChB,MAAM,KAAK,KAAK;AAAA,MAChB,KAAK,KAAK;AAAA;AAAA;AAAA,EAId,SAAS,WAAU;AACjB,QAAG,KAAK,KAAK,UAAS;AACpB,UAAI,WAAW,UAAU,KAAK,KAAK,aAAa,SAAS,8BAA8B,KAAK,KAAK;AACjG,aAAO,EAAC,MAAM,KAAK,KAAK,UAAU;AAAA,WAC7B;AACL,aAAO,EAAC,MAAM,WAAW,UAAU;AAAA;AAAA;AAAA,EAIvC,cAAc,MAAK;AACjB,SAAK,OAAO,KAAK,QAAQ,KAAK;AAC9B,QAAG,CAAC,KAAK,MAAK;AAAE,eAAS,kDAAkD,KAAK,OAAO,EAAC,OAAO,KAAK,QAAQ,UAAU;AAAA;AAAA;AAAA;;;AClG1H,IAAI,sBAAsB;AAE1B,yBAAkC;AAAA,SACzB,WAAW,MAAK;AACrB,QAAI,MAAM,KAAK;AACf,QAAG,QAAQ,QAAU;AACnB,aAAO;AAAA,WACF;AACL,WAAK,UAAW,wBAAuB;AACvC,aAAO,KAAK;AAAA;AAAA;AAAA,SAIT,gBAAgB,SAAS,KAAK,UAAS;AAC5C,QAAI,OAAO,KAAK,YAAY,SAAS,KAAK,WAAQ,KAAK,WAAW,WAAU;AAC5E,aAAS,IAAI,gBAAgB;AAAA;AAAA,SAGxB,qBAAqB,QAAO;AACjC,QAAI,SAAS;AACb,gBAAI,iBAAiB,QAAQ,QAAQ,WAAS;AAC5C,UAAG,MAAM,aAAa,0BAA0B,MAAM,aAAa,gBAAe;AAChF;AAAA;AAAA;AAGJ,WAAO,SAAS;AAAA;AAAA,SAGX,iBAAiB,SAAQ;AAC9B,QAAI,QAAQ,KAAK,YAAY;AAC7B,QAAI,WAAW;AACf,UAAM,QAAQ,UAAQ;AACpB,UAAI,QAAQ,EAAC,MAAM,QAAQ;AAC3B,UAAI,YAAY,QAAQ,aAAa;AACrC,eAAS,aAAa,SAAS,cAAc;AAC7C,YAAM,MAAM,KAAK,WAAW;AAC5B,YAAM,OAAO,KAAK,QAAQ,MAAM;AAChC,YAAM,OAAO,KAAK;AAClB,YAAM,OAAO,KAAK;AAClB,eAAS,WAAW,KAAK;AAAA;AAE3B,WAAO;AAAA;AAAA,SAGF,WAAW,SAAQ;AACxB,YAAQ,QAAQ;AAChB,YAAQ,gBAAgB;AACxB,gBAAI,WAAW,SAAS,SAAS;AAAA;AAAA,SAG5B,YAAY,SAAS,MAAK;AAC/B,gBAAI,WAAW,SAAS,SAAS,YAAI,QAAQ,SAAS,SAAS,OAAO,OAAK,CAAC,OAAO,GAAG,GAAG;AAAA;AAAA,SAGpF,WAAW,SAAS,OAAM;AAC/B,QAAG,QAAQ,aAAa,gBAAgB,MAAK;AAC3C,UAAI,WAAW,MAAM,OAAO,UAAQ,CAAC,KAAK,YAAY,SAAS,KAAK,OAAK,OAAO,GAAG,GAAG;AACtF,kBAAI,WAAW,SAAS,SAAS,KAAK,YAAY,SAAS,OAAO;AAClE,cAAQ,QAAQ;AAAA,WACX;AACL,kBAAI,WAAW,SAAS,SAAS;AAAA;AAAA;AAAA,SAI9B,iBAAiB,QAAO;AAC7B,QAAI,aAAa,YAAI,iBAAiB;AACtC,WAAO,MAAM,KAAK,YAAY,OAAO,QAAM,GAAG,SAAS,KAAK,YAAY,IAAI,SAAS;AAAA;AAAA,SAGhF,YAAY,OAAM;AACvB,WAAQ,aAAI,QAAQ,OAAO,YAAY,IAAI,OAAO,OAAK,YAAY,SAAS,OAAO;AAAA;AAAA,SAG9E,wBAAwB,QAAO;AACpC,QAAI,aAAa,YAAI,iBAAiB;AACtC,WAAO,MAAM,KAAK,YAAY,OAAO,WAAS,KAAK,uBAAuB,OAAO,SAAS;AAAA;AAAA,SAGrF,uBAAuB,OAAM;AAClC,WAAO,KAAK,YAAY,OAAO,OAAO,OAAK,CAAC,YAAY,cAAc,OAAO;AAAA;AAAA,EAG/E,YAAY,SAAS,MAAM,YAAW;AACpC,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,WACH,MAAM,KAAK,aAAa,uBAAuB,YAAY,IACxD,IAAI,UAAQ,IAAI,YAAY,SAAS,MAAM;AAEhD,SAAK,uBAAuB,KAAK,SAAS;AAAA;AAAA,EAG5C,UAAS;AAAE,WAAO,KAAK;AAAA;AAAA,EAEvB,kBAAkB,MAAM,SAAS,YAAW;AAC1C,SAAK,WACH,KAAK,SAAS,IAAI,WAAS;AACzB,YAAM,cAAc;AACpB,YAAM,OAAO,MAAM;AACjB,aAAK;AACL,YAAG,KAAK,yBAAyB,GAAE;AAAE,eAAK;AAAA;AAAA;AAE5C,aAAO;AAAA;AAGX,QAAI,iBAAiB,KAAK,SAAS,OAAO,CAAC,KAAK,UAAU;AACxD,UAAI,EAAC,MAAM,aAAY,MAAM,SAAS,WAAW;AACjD,UAAI,QAAQ,IAAI,SAAS,EAAC,UAAoB,SAAS;AACvD,UAAI,MAAM,QAAQ,KAAK;AACvB,aAAO;AAAA,OACN;AAEH,aAAQ,QAAQ,gBAAe;AAC7B,UAAI,EAAC,UAAU,YAAW,eAAe;AACzC,eAAS,SAAS,SAAS,MAAM;AAAA;AAAA;AAAA;;;ACrHvC,IAAI,QAAQ;AAAA,EACV,gBAAgB;AAAA,IACd,aAAY;AAAE,aAAO,KAAK,GAAG,aAAa;AAAA;AAAA,IAE1C,kBAAiB;AAAE,aAAO,KAAK,GAAG,aAAa;AAAA;AAAA,IAE/C,UAAS;AAAE,WAAK,iBAAiB,KAAK;AAAA;AAAA,IAEtC,UAAS;AACP,UAAI,gBAAgB,KAAK;AACzB,UAAG,KAAK,mBAAmB,eAAc;AACvC,aAAK,iBAAiB;AACtB,YAAG,kBAAkB,IAAG;AACtB,eAAK,OAAO,aAAa,KAAK,GAAG;AAAA;AAAA;AAIrC,UAAG,KAAK,iBAAiB,IAAG;AAAE,aAAK,GAAG,QAAQ;AAAA;AAC9C,WAAK,GAAG,cAAc,IAAI,YAAY;AAAA;AAAA;AAAA,EAI1C,gBAAgB;AAAA,IACd,UAAS;AACP,WAAK,MAAM,KAAK,GAAG,aAAa;AAChC,WAAK,UAAU,SAAS,eAAe,KAAK,GAAG,aAAa;AAC5D,mBAAa,gBAAgB,KAAK,SAAS,KAAK,KAAK,SAAO;AAC1D,aAAK,MAAM;AACX,aAAK,GAAG,MAAM;AAAA;AAAA;AAAA,IAGlB,YAAW;AACT,UAAI,gBAAgB,KAAK;AAAA;AAAA;AAAA;AAK/B,IAAO,gBAAQ;;;ACxCf,iCAA0C;AAAA,EACxC,YAAY,iBAAiB,gBAAgB,YAAW;AACtD,QAAI,YAAY,IAAI;AACpB,QAAI,WAAW,IAAI,IAAI,CAAC,GAAG,eAAe,UAAU,IAAI,WAAS,MAAM;AAEvE,QAAI,mBAAmB;AAEvB,UAAM,KAAK,gBAAgB,UAAU,QAAQ,WAAS;AACpD,UAAG,MAAM,IAAG;AACV,kBAAU,IAAI,MAAM;AACpB,YAAG,SAAS,IAAI,MAAM,KAAI;AACxB,cAAI,oBAAoB,MAAM,0BAA0B,MAAM,uBAAuB;AACrF,2BAAiB,KAAK,EAAC,WAAW,MAAM,IAAI;AAAA;AAAA;AAAA;AAKlD,SAAK,cAAc,eAAe;AAClC,SAAK,aAAa;AAClB,SAAK,mBAAmB;AACxB,SAAK,kBAAkB,CAAC,GAAG,UAAU,OAAO,QAAM,CAAC,UAAU,IAAI;AAAA;AAAA,EASnE,UAAS;AACP,QAAI,YAAY,YAAI,KAAK,KAAK;AAC9B,SAAK,iBAAiB,QAAQ,qBAAmB;AAC/C,UAAG,gBAAgB,mBAAkB;AACnC,cAAM,SAAS,eAAe,gBAAgB,oBAAoB,kBAAgB;AAChF,gBAAM,SAAS,eAAe,gBAAgB,YAAY,UAAQ;AAChE,gBAAI,iBAAiB,KAAK,0BAA0B,KAAK,uBAAuB,MAAM,aAAa;AACnG,gBAAG,CAAC,gBAAe;AACjB,2BAAa,sBAAsB,YAAY;AAAA;AAAA;AAAA;AAAA,aAIhD;AAEL,cAAM,SAAS,eAAe,gBAAgB,YAAY,UAAQ;AAChE,cAAI,iBAAiB,KAAK,0BAA0B;AACpD,cAAG,CAAC,gBAAe;AACjB,sBAAU,sBAAsB,cAAc;AAAA;AAAA;AAAA;AAAA;AAMtD,QAAG,KAAK,cAAc,WAAU;AAC9B,WAAK,gBAAgB,UAAU,QAAQ,YAAU;AAC/C,cAAM,SAAS,eAAe,SAAS,UAAQ,UAAU,sBAAsB,cAAc;AAAA;AAAA;AAAA;AAAA;;;AC5DrG,IAAI,yBAAyB;AAE7B,oBAAoB,UAAU,QAAQ;AAClC,MAAI,cAAc,OAAO;AACzB,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AAGJ,MAAI,OAAO,aAAa,0BAA0B,SAAS,aAAa,wBAAwB;AAC9F;AAAA;AAIF,WAAS,IAAI,YAAY,SAAS,GAAG,KAAK,GAAG,KAAK;AAC9C,WAAO,YAAY;AACnB,eAAW,KAAK;AAChB,uBAAmB,KAAK;AACxB,gBAAY,KAAK;AAEjB,QAAI,kBAAkB;AAClB,iBAAW,KAAK,aAAa;AAC7B,kBAAY,SAAS,eAAe,kBAAkB;AAEtD,UAAI,cAAc,WAAW;AACzB,YAAI,KAAK,WAAW,SAAQ;AACxB,qBAAW,KAAK;AAAA;AAEpB,iBAAS,eAAe,kBAAkB,UAAU;AAAA;AAAA,WAErD;AACH,kBAAY,SAAS,aAAa;AAElC,UAAI,cAAc,WAAW;AACzB,iBAAS,aAAa,UAAU;AAAA;AAAA;AAAA;AAO5C,MAAI,gBAAgB,SAAS;AAE7B,WAAS,IAAI,cAAc,SAAS,GAAG,KAAK,GAAG,KAAK;AAChD,WAAO,cAAc;AACrB,eAAW,KAAK;AAChB,uBAAmB,KAAK;AAExB,QAAI,kBAAkB;AAClB,iBAAW,KAAK,aAAa;AAE7B,UAAI,CAAC,OAAO,eAAe,kBAAkB,WAAW;AACpD,iBAAS,kBAAkB,kBAAkB;AAAA;AAAA,WAE9C;AACH,UAAI,CAAC,OAAO,aAAa,WAAW;AAChC,iBAAS,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAMzC,IAAI;AACJ,IAAI,WAAW;AAEf,IAAI,MAAM,OAAO,aAAa,cAAc,SAAY;AACxD,IAAI,uBAAuB,CAAC,CAAC,OAAO,aAAa,IAAI,cAAc;AACnE,IAAI,oBAAoB,CAAC,CAAC,OAAO,IAAI,eAAe,8BAA8B,IAAI;AAEtF,oCAAoC,KAAK;AACrC,MAAI,WAAW,IAAI,cAAc;AACjC,WAAS,YAAY;AACrB,SAAO,SAAS,QAAQ,WAAW;AAAA;AAGvC,iCAAiC,KAAK;AAClC,MAAI,CAAC,OAAO;AACR,YAAQ,IAAI;AACZ,UAAM,WAAW,IAAI;AAAA;AAGzB,MAAI,WAAW,MAAM,yBAAyB;AAC9C,SAAO,SAAS,WAAW;AAAA;AAG/B,gCAAgC,KAAK;AACjC,MAAI,WAAW,IAAI,cAAc;AACjC,WAAS,YAAY;AACrB,SAAO,SAAS,WAAW;AAAA;AAW/B,mBAAmB,KAAK;AACpB,QAAM,IAAI;AACV,MAAI,sBAAsB;AAIxB,WAAO,2BAA2B;AAAA,aACzB,mBAAmB;AAC5B,WAAO,wBAAwB;AAAA;AAGjC,SAAO,uBAAuB;AAAA;AAalC,0BAA0B,QAAQ,MAAM;AACpC,MAAI,eAAe,OAAO;AAC1B,MAAI,aAAa,KAAK;AACtB,MAAI,eAAe;AAEnB,MAAI,iBAAiB,YAAY;AAC7B,WAAO;AAAA;AAGX,kBAAgB,aAAa,WAAW;AACxC,gBAAc,WAAW,WAAW;AAMpC,MAAI,iBAAiB,MAAM,eAAe,IAAI;AAC1C,WAAO,iBAAiB,WAAW;AAAA,aAC5B,eAAe,MAAM,iBAAiB,IAAI;AACjD,WAAO,eAAe,aAAa;AAAA,SAChC;AACH,WAAO;AAAA;AAAA;AAaf,yBAAyB,MAAM,cAAc;AACzC,SAAO,CAAC,gBAAgB,iBAAiB,WACrC,IAAI,cAAc,QAClB,IAAI,gBAAgB,cAAc;AAAA;AAM1C,sBAAsB,QAAQ,MAAM;AAChC,MAAI,WAAW,OAAO;AACtB,SAAO,UAAU;AACb,QAAI,YAAY,SAAS;AACzB,SAAK,YAAY;AACjB,eAAW;AAAA;AAEf,SAAO;AAAA;AAGX,6BAA6B,QAAQ,MAAM,MAAM;AAC7C,MAAI,OAAO,UAAU,KAAK,OAAO;AAC7B,WAAO,QAAQ,KAAK;AACpB,QAAI,OAAO,OAAO;AACd,aAAO,aAAa,MAAM;AAAA,WACvB;AACH,aAAO,gBAAgB;AAAA;AAAA;AAAA;AAKnC,IAAI,oBAAoB;AAAA,EACpB,QAAQ,SAAS,QAAQ,MAAM;AAC3B,QAAI,aAAa,OAAO;AACxB,QAAI,YAAY;AACZ,UAAI,aAAa,WAAW,SAAS;AACrC,UAAI,eAAe,YAAY;AAC3B,qBAAa,WAAW;AACxB,qBAAa,cAAc,WAAW,SAAS;AAAA;AAEnD,UAAI,eAAe,YAAY,CAAC,WAAW,aAAa,aAAa;AACjE,YAAI,OAAO,aAAa,eAAe,CAAC,KAAK,UAAU;AAInD,iBAAO,aAAa,YAAY;AAChC,iBAAO,gBAAgB;AAAA;AAK3B,mBAAW,gBAAgB;AAAA;AAAA;AAGnC,wBAAoB,QAAQ,MAAM;AAAA;AAAA,EAQtC,OAAO,SAAS,QAAQ,MAAM;AAC1B,wBAAoB,QAAQ,MAAM;AAClC,wBAAoB,QAAQ,MAAM;AAElC,QAAI,OAAO,UAAU,KAAK,OAAO;AAC7B,aAAO,QAAQ,KAAK;AAAA;AAGxB,QAAI,CAAC,KAAK,aAAa,UAAU;AAC7B,aAAO,gBAAgB;AAAA;AAAA;AAAA,EAI/B,UAAU,SAAS,QAAQ,MAAM;AAC7B,QAAI,WAAW,KAAK;AACpB,QAAI,OAAO,UAAU,UAAU;AAC3B,aAAO,QAAQ;AAAA;AAGnB,QAAI,aAAa,OAAO;AACxB,QAAI,YAAY;AAGZ,UAAI,WAAW,WAAW;AAE1B,UAAI,YAAY,YAAa,CAAC,YAAY,YAAY,OAAO,aAAc;AACvE;AAAA;AAGJ,iBAAW,YAAY;AAAA;AAAA;AAAA,EAG/B,QAAQ,SAAS,QAAQ,MAAM;AAC3B,QAAI,CAAC,KAAK,aAAa,aAAa;AAChC,UAAI,gBAAgB;AACpB,UAAI,IAAI;AAKR,UAAI,WAAW,OAAO;AACtB,UAAI;AACJ,UAAI;AACJ,aAAM,UAAU;AACZ,mBAAW,SAAS,YAAY,SAAS,SAAS;AAClD,YAAI,aAAa,YAAY;AACzB,qBAAW;AACX,qBAAW,SAAS;AAAA,eACjB;AACH,cAAI,aAAa,UAAU;AACvB,gBAAI,SAAS,aAAa,aAAa;AACnC,8BAAgB;AAChB;AAAA;AAEJ;AAAA;AAEJ,qBAAW,SAAS;AACpB,cAAI,CAAC,YAAY,UAAU;AACvB,uBAAW,SAAS;AACpB,uBAAW;AAAA;AAAA;AAAA;AAKvB,aAAO,gBAAgB;AAAA;AAAA;AAAA;AAKnC,IAAI,eAAe;AACnB,IAAI,2BAA2B;AAC/B,IAAI,YAAY;AAChB,IAAI,eAAe;AAEnB,gBAAgB;AAAA;AAEhB,2BAA2B,MAAM;AAC/B,MAAI,MAAM;AACN,WAAQ,KAAK,gBAAgB,KAAK,aAAa,SAAU,KAAK;AAAA;AAAA;AAIpE,yBAAyB,aAAY;AAEjC,SAAO,mBAAkB,UAAU,QAAQ,SAAS;AAChD,QAAI,CAAC,SAAS;AACV,gBAAU;AAAA;AAGd,QAAI,OAAO,WAAW,UAAU;AAC5B,UAAI,SAAS,aAAa,eAAe,SAAS,aAAa,UAAU,SAAS,aAAa,QAAQ;AACnG,YAAI,aAAa;AACjB,iBAAS,IAAI,cAAc;AAC3B,eAAO,YAAY;AAAA,aAChB;AACH,iBAAS,UAAU;AAAA;AAAA;AAI3B,QAAI,aAAa,QAAQ,cAAc;AACvC,QAAI,oBAAoB,QAAQ,qBAAqB;AACrD,QAAI,cAAc,QAAQ,eAAe;AACzC,QAAI,oBAAoB,QAAQ,qBAAqB;AACrD,QAAI,cAAc,QAAQ,eAAe;AACzC,QAAI,wBAAwB,QAAQ,yBAAyB;AAC7D,QAAI,kBAAkB,QAAQ,mBAAmB;AACjD,QAAI,4BAA4B,QAAQ,6BAA6B;AACrE,QAAI,eAAe,QAAQ,iBAAiB;AAG5C,QAAI,kBAAkB,OAAO,OAAO;AACpC,QAAI,mBAAmB;AAEvB,6BAAyB,KAAK;AAC1B,uBAAiB,KAAK;AAAA;AAG1B,qCAAiC,MAAM,gBAAgB;AACnD,UAAI,KAAK,aAAa,cAAc;AAChC,YAAI,WAAW,KAAK;AACpB,eAAO,UAAU;AAEb,cAAI,MAAM;AAEV,cAAI,kBAAmB,OAAM,WAAW,YAAY;AAGhD,4BAAgB;AAAA,iBACb;AAIH,4BAAgB;AAChB,gBAAI,SAAS,YAAY;AACrB,sCAAwB,UAAU;AAAA;AAAA;AAI1C,qBAAW,SAAS;AAAA;AAAA;AAAA;AAahC,wBAAoB,MAAM,YAAY,gBAAgB;AAClD,UAAI,sBAAsB,UAAU,OAAO;AACvC;AAAA;AAGJ,UAAI,YAAY;AACZ,mBAAW,YAAY;AAAA;AAG3B,sBAAgB;AAChB,8BAAwB,MAAM;AAAA;AA+BlC,uBAAmB,MAAM;AACrB,UAAI,KAAK,aAAa,gBAAgB,KAAK,aAAa,0BAA0B;AAC9E,YAAI,WAAW,KAAK;AACpB,eAAO,UAAU;AACb,cAAI,MAAM,WAAW;AACrB,cAAI,KAAK;AACL,4BAAgB,OAAO;AAAA;AAI3B,oBAAU;AAEV,qBAAW,SAAS;AAAA;AAAA;AAAA;AAKhC,cAAU;AAEV,6BAAyB,IAAI;AACzB,kBAAY;AAEZ,UAAI,WAAW,GAAG;AAClB,aAAO,UAAU;AACb,YAAI,cAAc,SAAS;AAE3B,YAAI,MAAM,WAAW;AACrB,YAAI,KAAK;AACL,cAAI,kBAAkB,gBAAgB;AAGtC,cAAI,mBAAmB,iBAAiB,UAAU,kBAAkB;AAChE,qBAAS,WAAW,aAAa,iBAAiB;AAClD,oBAAQ,iBAAiB;AAAA,iBACtB;AACL,4BAAgB;AAAA;AAAA,eAEf;AAGL,0BAAgB;AAAA;AAGlB,mBAAW;AAAA;AAAA;AAInB,2BAAuB,QAAQ,kBAAkB,gBAAgB;AAI7D,aAAO,kBAAkB;AACrB,YAAI,kBAAkB,iBAAiB;AACvC,YAAK,iBAAiB,WAAW,mBAAoB;AAGjD,0BAAgB;AAAA,eACb;AAGH,qBAAW,kBAAkB,QAAQ;AAAA;AAEzC,2BAAmB;AAAA;AAAA;AAI3B,qBAAiB,QAAQ,MAAM,eAAc;AACzC,UAAI,UAAU,WAAW;AAEzB,UAAI,SAAS;AAGT,eAAO,gBAAgB;AAAA;AAG3B,UAAI,CAAC,eAAc;AAEf,YAAI,kBAAkB,QAAQ,UAAU,OAAO;AAC3C;AAAA;AAIJ,oBAAW,QAAQ;AAEnB,oBAAY;AAEZ,YAAI,0BAA0B,QAAQ,UAAU,OAAO;AACnD;AAAA;AAAA;AAIR,UAAI,OAAO,aAAa,YAAY;AAClC,sBAAc,QAAQ;AAAA,aACjB;AACL,0BAAkB,SAAS,QAAQ;AAAA;AAAA;AAIzC,2BAAuB,QAAQ,MAAM;AACjC,UAAI,iBAAiB,KAAK;AAC1B,UAAI,mBAAmB,OAAO;AAC9B,UAAI;AACJ,UAAI;AAEJ,UAAI;AACJ,UAAI;AACJ,UAAI;AAGJ;AAAO,eAAO,gBAAgB;AAC1B,0BAAgB,eAAe;AAC/B,yBAAe,WAAW;AAG1B,iBAAO,kBAAkB;AACrB,8BAAkB,iBAAiB;AAEnC,gBAAI,eAAe,cAAc,eAAe,WAAW,mBAAmB;AAC1E,+BAAiB;AACjB,iCAAmB;AACnB;AAAA;AAGJ,6BAAiB,WAAW;AAE5B,gBAAI,kBAAkB,iBAAiB;AAGvC,gBAAI,eAAe;AAEnB,gBAAI,oBAAoB,eAAe,UAAU;AAC7C,kBAAI,oBAAoB,cAAc;AAGlC,oBAAI,cAAc;AAGd,sBAAI,iBAAiB,gBAAgB;AAIjC,wBAAK,iBAAiB,gBAAgB,eAAgB;AAClD,0BAAI,oBAAoB,gBAAgB;AAMpC,uCAAe;AAAA,6BACZ;AAQH,+BAAO,aAAa,gBAAgB;AAIpC,4BAAI,gBAAgB;AAGhB,0CAAgB;AAAA,+BACb;AAGH,qCAAW,kBAAkB,QAAQ;AAAA;AAGzC,2CAAmB;AAAA;AAAA,2BAEpB;AAGH,qCAAe;AAAA;AAAA;AAAA,2BAGhB,gBAAgB;AAEvB,iCAAe;AAAA;AAGnB,+BAAe,iBAAiB,SAAS,iBAAiB,kBAAkB;AAC5E,oBAAI,cAAc;AAKd,0BAAQ,kBAAkB;AAAA;AAAA,yBAGvB,oBAAoB,aAAa,mBAAmB,cAAc;AAEzE,+BAAe;AAGf,oBAAI,iBAAiB,cAAc,eAAe,WAAW;AACzD,mCAAiB,YAAY,eAAe;AAAA;AAAA;AAAA;AAMxD,gBAAI,cAAc;AAGd,+BAAiB;AACjB,iCAAmB;AACnB;AAAA;AASJ,gBAAI,gBAAgB;AAGhB,8BAAgB;AAAA,mBACb;AAGH,yBAAW,kBAAkB,QAAQ;AAAA;AAGzC,+BAAmB;AAAA;AAOvB,cAAI,gBAAiB,kBAAiB,gBAAgB,kBAAkB,iBAAiB,gBAAgB,iBAAiB;AACtH,mBAAO,YAAY;AAEnB,oBAAQ,gBAAgB;AAAA,iBACrB;AACH,gBAAI,0BAA0B,kBAAkB;AAChD,gBAAI,4BAA4B,OAAO;AACnC,kBAAI,yBAAyB;AACzB,iCAAiB;AAAA;AAGrB,kBAAI,eAAe,WAAW;AAC1B,iCAAiB,eAAe,UAAU,OAAO,iBAAiB;AAAA;AAEtE,qBAAO,YAAY;AACnB,8BAAgB;AAAA;AAAA;AAIxB,2BAAiB;AACjB,6BAAmB;AAAA;AAGvB,oBAAc,QAAQ,kBAAkB;AAExC,UAAI,mBAAmB,kBAAkB,OAAO;AAChD,UAAI,kBAAkB;AAClB,yBAAiB,QAAQ;AAAA;AAAA;AAIjC,QAAI,cAAc;AAClB,QAAI,kBAAkB,YAAY;AAClC,QAAI,aAAa,OAAO;AAExB,QAAI,CAAC,cAAc;AAGf,UAAI,oBAAoB,cAAc;AAClC,YAAI,eAAe,cAAc;AAC7B,cAAI,CAAC,iBAAiB,UAAU,SAAS;AACrC,4BAAgB;AAChB,0BAAc,aAAa,UAAU,gBAAgB,OAAO,UAAU,OAAO;AAAA;AAAA,eAE9E;AAEH,wBAAc;AAAA;AAAA,iBAEX,oBAAoB,aAAa,oBAAoB,cAAc;AAC1E,YAAI,eAAe,iBAAiB;AAChC,cAAI,YAAY,cAAc,OAAO,WAAW;AAC5C,wBAAY,YAAY,OAAO;AAAA;AAGnC,iBAAO;AAAA,eACJ;AAEH,wBAAc;AAAA;AAAA;AAAA;AAK1B,QAAI,gBAAgB,QAAQ;AAGxB,sBAAgB;AAAA,WACb;AACH,UAAI,OAAO,cAAc,OAAO,WAAW,cAAc;AACrD;AAAA;AAGJ,cAAQ,aAAa,QAAQ;AAO7B,UAAI,kBAAkB;AAClB,iBAAS,IAAE,GAAG,MAAI,iBAAiB,QAAQ,IAAE,KAAK,KAAK;AACnD,cAAI,aAAa,gBAAgB,iBAAiB;AAClD,cAAI,YAAY;AACZ,uBAAW,YAAY,WAAW,YAAY;AAAA;AAAA;AAAA;AAAA;AAM9D,QAAI,CAAC,gBAAgB,gBAAgB,YAAY,SAAS,YAAY;AAClE,UAAI,YAAY,WAAW;AACvB,sBAAc,YAAY,UAAU,SAAS,iBAAiB;AAAA;AAOlE,eAAS,WAAW,aAAa,aAAa;AAAA;AAGlD,WAAO;AAAA;AAAA;AAIf,IAAI,WAAW,gBAAgB;AAE/B,IAAO,uBAAQ;;;AC5tBf,qBAA8B;AAAA,SACrB,QAAQ,QAAQ,MAAM,eAAc;AACzC,yBAAS,QAAQ,MAAM;AAAA,MACrB,cAAc;AAAA,MACd,mBAAmB,CAAC,SAAQ,UAAS;AACnC,YAAG,iBAAiB,cAAc,WAAW,YAAW,YAAI,YAAY,UAAQ;AAC9E,sBAAI,kBAAkB,SAAQ;AAC9B,iBAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf,YAAY,MAAM,WAAW,IAAI,MAAM,WAAU;AAC/C,SAAK,OAAO;AACZ,SAAK,aAAa,KAAK;AACvB,SAAK,YAAY;AACjB,SAAK,KAAK;AACV,SAAK,SAAS,KAAK,KAAK;AACxB,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,WAAW,MAAM,KAAK;AAC3B,SAAK,YAAY;AAAA,MACf,aAAa;AAAA,MAAI,eAAe;AAAA,MAAI,qBAAqB;AAAA,MACzD,YAAY;AAAA,MAAI,cAAc;AAAA,MAAI,gBAAgB;AAAA,MAAI,oBAAoB;AAAA,MAC1E,2BAA2B;AAAA;AAAA;AAAA,EAI/B,OAAO,MAAM,UAAS;AAAE,SAAK,UAAU,SAAS,QAAQ,KAAK;AAAA;AAAA,EAC7D,MAAM,MAAM,UAAS;AAAE,SAAK,UAAU,QAAQ,QAAQ,KAAK;AAAA;AAAA,EAE3D,YAAY,SAAS,MAAK;AACxB,SAAK,UAAU,SAAS,QAAQ,QAAQ,cAAY,SAAS,GAAG;AAAA;AAAA,EAGlE,WAAW,SAAS,MAAK;AACvB,SAAK,UAAU,QAAQ,QAAQ,QAAQ,cAAY,SAAS,GAAG;AAAA;AAAA,EAGjE,gCAA+B;AAC7B,gBAAI,IAAI,KAAK,WAAW,qDAAqD,QAAM;AACjF,SAAG,aAAa,WAAW;AAAA;AAAA;AAAA,EAI/B,UAAS;AACP,QAAI,EAAC,MAAM,YAAY,WAAW,SAAQ;AAC1C,QAAI,kBAAkB,KAAK,eAAe,KAAK,mBAAmB,QAAQ;AAC1E,QAAG,KAAK,gBAAgB,CAAC,iBAAgB;AAAE;AAAA;AAE3C,QAAI,UAAU,WAAW;AACzB,QAAI,EAAC,gBAAgB,iBAAgB,WAAW,YAAI,kBAAkB,WAAW,UAAU;AAC3F,QAAI,YAAY,WAAW,QAAQ;AACnC,QAAI,iBAAiB,WAAW,QAAQ;AACxC,QAAI,cAAc,WAAW,QAAQ;AACrC,QAAI,qBAAqB,WAAW,QAAQ;AAC5C,QAAI,YAAY,WAAW,QAAQ;AACnC,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,QAAI,uBAAuB;AAC3B,QAAI,iBAAiB;AACrB,QAAI,wBAAwB;AAE5B,QAAI,WAAW,WAAW,KAAK,2BAA2B,MAAM;AAC9D,aAAO,KAAK,cAAc,WAAW,MAAM,WAAW;AAAA;AAGxD,SAAK,YAAY,SAAS;AAC1B,SAAK,YAAY,WAAW,WAAW;AAEvC,eAAW,KAAK,YAAY,MAAM;AAChC,2BAAS,iBAAiB,UAAU;AAAA,QAClC,cAAc,gBAAgB,aAAa,mBAAmB;AAAA,QAC9D,YAAY,CAAC,SAAS;AACpB,iBAAO,YAAI,eAAe,QAAQ,OAAO,KAAK;AAAA;AAAA,QAEhD,mBAAmB,CAAC,OAAO;AACzB,eAAK,YAAY,SAAS;AAC1B,iBAAO;AAAA;AAAA,QAET,aAAa,CAAC,OAAO;AAEnB,cAAG,cAAc,oBAAoB,GAAG,QAAO;AAC7C,eAAG,SAAS,GAAG;AAAA,qBACP,cAAc,oBAAoB,GAAG,UAAS;AACtD,eAAG;AAAA;AAEL,cAAG,YAAI,yBAAyB,IAAI,qBAAoB;AACtD,oCAAwB;AAAA;AAG1B,sBAAI,aAAa,iBAAiB,IAAI;AAEtC,cAAI,YAAI,WAAW,OAAO,KAAK,YAAY,OAAQ,YAAI,YAAY,OAAO,KAAK,YAAY,GAAG,aAAY;AACxG,iBAAK,WAAW,iBAAiB;AAAA;AAEnC,gBAAM,KAAK;AAAA;AAAA,QAEb,iBAAiB,CAAC,OAAO;AAEvB,cAAG,YAAI,WAAW,OAAO,YAAI,YAAY,KAAI;AAAE,uBAAW,gBAAgB;AAAA;AAC1E,eAAK,WAAW,aAAa;AAAA;AAAA,QAE/B,uBAAuB,CAAC,OAAO;AAC7B,cAAG,GAAG,gBAAgB,GAAG,aAAa,eAAe,MAAK;AAAE,mBAAO;AAAA;AACnE,cAAG,GAAG,eAAe,QAAQ,YAAI,YAAY,GAAG,YAAY,WAAW,CAAC,UAAU,eAAe,GAAG,IAAG;AAAE,mBAAO;AAAA;AAChH,cAAG,GAAG,gBAAgB,GAAG,aAAa,YAAW;AAC/C,2BAAe,KAAK;AACpB,mBAAO;AAAA;AAET,cAAG,KAAK,eAAe,KAAI;AAAE,mBAAO;AAAA;AACpC,iBAAO;AAAA;AAAA,QAET,aAAa,CAAC,OAAO;AACnB,cAAG,YAAI,yBAAyB,IAAI,qBAAoB;AACtD,oCAAwB;AAAA;AAE1B,kBAAQ,KAAK;AAAA;AAAA,QAEf,mBAAmB,CAAC,QAAQ,SAAS;AACnC,sBAAI,gBAAgB,MAAM;AAC1B,cAAG,KAAK,eAAe,OAAM;AAAE,mBAAO;AAAA;AACtC,cAAG,YAAI,YAAY,SAAQ;AAAE,mBAAO;AAAA;AACpC,cAAG,YAAI,UAAU,QAAQ,YAAW;AAClC,iBAAK,YAAY,WAAW,QAAQ;AACpC,wBAAI,WAAW,QAAQ,MAAM,EAAC,WAAW;AACzC,oBAAQ,KAAK;AACb,wBAAI,sBAAsB;AAC1B,mBAAO;AAAA;AAET,cAAG,OAAO,SAAS,YAAa,QAAO,YAAY,OAAO,SAAS,WAAU;AAAE,mBAAO;AAAA;AACtF,cAAG,CAAC,YAAI,eAAe,QAAQ,MAAM,cAAa;AAChD,gBAAG,YAAI,cAAc,SAAQ;AAC3B,mBAAK,YAAY,WAAW,QAAQ;AACpC,sBAAQ,KAAK;AAAA;AAEf,wBAAI,sBAAsB;AAC1B,mBAAO;AAAA;AAIT,cAAG,YAAI,WAAW,OAAM;AACtB,gBAAI,cAAc,OAAO,aAAa;AACtC,wBAAI,WAAW,QAAQ,MAAM,EAAC,SAAS,CAAC;AACxC,gBAAG,gBAAgB,IAAG;AAAE,qBAAO,aAAa,aAAa;AAAA;AACzD,mBAAO,aAAa,aAAa,KAAK;AACtC,wBAAI,sBAAsB;AAC1B,mBAAO;AAAA;AAIT,sBAAI,aAAa,MAAM;AACvB,sBAAI,aAAa,iBAAiB,MAAM;AAExC,cAAI,kBAAkB,WAAW,OAAO,WAAW,YAAY,YAAI,YAAY;AAC/E,cAAG,iBAAgB;AACjB,iBAAK,YAAY,WAAW,QAAQ;AACpC,wBAAI,kBAAkB,QAAQ;AAC9B,wBAAI,iBAAiB;AACrB,oBAAQ,KAAK;AACb,wBAAI,sBAAsB;AAC1B,mBAAO;AAAA,iBACF;AACL,gBAAG,YAAI,YAAY,MAAM,WAAW,CAAC,UAAU,aAAY;AACzD,mCAAqB,KAAK,IAAI,qBAAqB,QAAQ,MAAM,KAAK,aAAa;AAAA;AAErF,wBAAI,iBAAiB;AACrB,wBAAI,sBAAsB;AAC1B,iBAAK,YAAY,WAAW,QAAQ;AACpC,mBAAO;AAAA;AAAA;AAAA;AAAA;AAMf,QAAG,WAAW,kBAAiB;AAAE;AAAA;AAEjC,QAAG,qBAAqB,SAAS,GAAE;AACjC,iBAAW,KAAK,yCAAyC,MAAM;AAC7D,6BAAqB,QAAQ,YAAU,OAAO;AAAA;AAAA;AAIlD,eAAW,cAAc,MAAM,YAAI,aAAa,SAAS,gBAAgB;AACzE,gBAAI,cAAc,UAAU;AAC5B,UAAM,QAAQ,QAAM,KAAK,WAAW,SAAS;AAC7C,YAAQ,QAAQ,QAAM,KAAK,WAAW,WAAW;AAEjD,QAAG,eAAe,SAAS,GAAE;AAC3B,iBAAW,kBAAkB;AAC7B,iBAAW,iBAAiB,MAAM;AAChC,uBAAe,QAAQ,QAAM;AAC3B,cAAI,QAAQ,YAAI,cAAc;AAC9B,cAAG,OAAM;AAAE,uBAAW,gBAAgB;AAAA;AACtC,aAAG;AAAA;AAEL,aAAK,WAAW,wBAAwB;AAAA;AAAA;AAI5C,QAAG,uBAAsB;AACvB,iBAAW;AACX,4BAAsB;AAAA;AAExB,WAAO;AAAA;AAAA,EAGT,aAAY;AAAE,WAAO,KAAK;AAAA;AAAA,EAE1B,eAAe,IAAG;AAChB,WAAO,GAAG,aAAa,KAAK,gBAAgB,GAAG,aAAa,cAAc;AAAA;AAAA,EAG5E,mBAAmB,MAAK;AACtB,QAAG,CAAC,KAAK,cAAa;AAAE;AAAA;AACxB,QAAI,CAAC,UAAU,QAAQ,YAAI,sBAAsB,KAAK,WAAW,KAAK;AACtE,QAAG,KAAK,WAAW,KAAK,YAAI,gBAAgB,UAAU,GAAE;AACtD,aAAO;AAAA,WACF;AACL,aAAO,SAAS,MAAM;AAAA;AAAA;AAAA,EAU1B,cAAc,WAAW,MAAM,WAAW,iBAAgB;AACxD,QAAI,aAAa,KAAK;AACtB,QAAI,sBAAsB,cAAc,gBAAgB,aAAa,mBAAmB,KAAK,UAAU;AACvG,QAAG,CAAC,cAAc,qBAAoB;AACpC,aAAO;AAAA,WACF;AAEL,UAAI,gBAAgB;AACpB,UAAI,WAAW,SAAS,cAAc;AACtC,sBAAgB,YAAI,UAAU;AAC9B,UAAI,CAAC,mBAAmB,QAAQ,YAAI,sBAAsB,eAAe,KAAK;AAC9E,eAAS,YAAY;AACrB,WAAK,QAAQ,QAAM,GAAG;AACtB,YAAM,KAAK,cAAc,YAAY,QAAQ,WAAS;AAEpD,YAAG,MAAM,MAAM,MAAM,aAAa,KAAK,gBAAgB,MAAM,aAAa,mBAAmB,KAAK,UAAU,YAAW;AACrH,gBAAM,aAAa,UAAU;AAC7B,gBAAM,YAAY;AAAA;AAAA;AAGtB,YAAM,KAAK,SAAS,QAAQ,YAAY,QAAQ,QAAM,cAAc,aAAa,IAAI;AACrF,qBAAe;AACf,aAAO,cAAc;AAAA;AAAA;AAAA;;;AChQ3B,qBAA8B;AAAA,SACrB,QAAQ,MAAK;AAClB,QAAI,GAAE,QAAQ,QAAQ,SAAS,SAAS,QAAQ,UAAS;AACzD,WAAO,KAAK;AACZ,WAAO,KAAK;AACZ,WAAO,KAAK;AACZ,WAAO,EAAC,MAAM,OAAO,OAAO,SAAS,MAAM,QAAQ,UAAU;AAAA;AAAA,EAG/D,YAAY,QAAQ,UAAS;AAC3B,SAAK,SAAS;AACd,SAAK,WAAW;AAChB,SAAK,UAAU;AAAA;AAAA,EAGjB,eAAc;AAAE,WAAO,KAAK;AAAA;AAAA,EAE5B,SAAS,UAAS;AAChB,WAAO,KAAK,kBAAkB,KAAK,UAAU,KAAK,SAAS,aAAa;AAAA;AAAA,EAG1E,kBAAkB,UAAU,aAAa,SAAS,aAAa,UAAS;AACtE,eAAW,WAAW,IAAI,IAAI,YAAY;AAC1C,QAAI,SAAS,EAAC,QAAQ,IAAI,YAAwB;AAClD,SAAK,eAAe,UAAU,MAAM;AACpC,WAAO,OAAO;AAAA;AAAA,EAGhB,cAAc,MAAK;AAAE,WAAO,OAAO,KAAK,KAAK,eAAe,IAAI,IAAI,OAAK,SAAS;AAAA;AAAA,EAElF,oBAAoB,MAAK;AACvB,QAAG,CAAC,KAAK,aAAY;AAAE,aAAO;AAAA;AAC9B,WAAO,OAAO,KAAK,MAAM,WAAW;AAAA;AAAA,EAGtC,aAAa,MAAM,KAAI;AAAE,WAAO,KAAK,YAAY;AAAA;AAAA,EAEjD,UAAU,MAAK;AACb,QAAI,OAAO,KAAK;AAChB,QAAI,QAAQ;AACZ,WAAO,KAAK;AACZ,SAAK,WAAW,KAAK,aAAa,KAAK,UAAU;AACjD,SAAK,SAAS,cAAc,KAAK,SAAS,eAAe;AAEzD,QAAG,MAAK;AACN,UAAI,OAAO,KAAK,SAAS;AAEzB,eAAQ,OAAO,MAAK;AAClB,aAAK,OAAO,KAAK,oBAAoB,KAAK,KAAK,MAAM,MAAM,MAAM;AAAA;AAGnE,eAAQ,OAAO,MAAK;AAAE,aAAK,OAAO,KAAK;AAAA;AACvC,WAAK,cAAc;AAAA;AAAA;AAAA,EAIvB,oBAAoB,KAAK,OAAO,MAAM,MAAM,OAAM;AAChD,QAAG,MAAM,MAAK;AACZ,aAAO,MAAM;AAAA,WACR;AACL,UAAI,OAAO,MAAM,OAAO,MAAM;AAE9B,UAAG,MAAM,OAAM;AACb,YAAI;AAEJ,YAAG,OAAO,GAAE;AACV,kBAAQ,KAAK,oBAAoB,MAAM,KAAK,OAAO,MAAM,MAAM;AAAA,eAC1D;AACL,kBAAQ,KAAK,CAAC;AAAA;AAGhB,eAAO,MAAM;AACb,gBAAQ,KAAK,WAAW,OAAO;AAC/B,cAAM,UAAU;AAAA,aACX;AACL,gBAAQ,MAAM,YAAY,SAAY,QAAQ,KAAK,WAAW,KAAK,QAAQ,IAAI;AAAA;AAGjF,YAAM,OAAO;AACb,aAAO;AAAA;AAAA;AAAA,EAIX,aAAa,QAAQ,QAAO;AAC1B,QAAG,OAAO,YAAY,QAAU;AAC9B,aAAO;AAAA,WACF;AACL,WAAK,eAAe,QAAQ;AAC5B,aAAO;AAAA;AAAA;AAAA,EAIX,eAAe,QAAQ,QAAO;AAC5B,aAAQ,OAAO,QAAO;AACpB,UAAI,MAAM,OAAO;AACjB,UAAI,YAAY,OAAO;AACvB,UAAG,SAAS,QAAQ,IAAI,YAAY,UAAa,SAAS,YAAW;AACnE,aAAK,eAAe,WAAW;AAAA,aAC1B;AACL,eAAO,OAAO;AAAA;AAAA;AAAA;AAAA,EAKpB,WAAW,QAAQ,QAAO;AACxB,QAAI,SAAS,KAAI,WAAW;AAC5B,aAAQ,OAAO,QAAO;AACpB,UAAI,MAAM,OAAO;AACjB,UAAI,YAAY,OAAO;AACvB,UAAG,SAAS,QAAQ,IAAI,YAAY,UAAa,SAAS,YAAW;AACnE,eAAO,OAAO,KAAK,WAAW,WAAW;AAAA;AAAA;AAG7C,WAAO;AAAA;AAAA,EAGT,kBAAkB,KAAI;AAAE,WAAO,KAAK,qBAAqB,KAAK,SAAS,aAAa;AAAA;AAAA,EAEpF,UAAU,MAAK;AACb,SAAK,QAAQ,SAAO,OAAO,KAAK,SAAS,YAAY;AAAA;AAAA,EAKvD,MAAK;AAAE,WAAO,KAAK;AAAA;AAAA,EAEnB,iBAAiB,OAAO,IAAG;AAAE,WAAO,CAAC,CAAC,KAAK;AAAA;AAAA,EAE3C,eAAe,MAAM,WAAU;AAC7B,QAAG,OAAQ,SAAU,UAAU;AAC7B,aAAO,UAAU;AAAA,WACZ;AACL,aAAO;AAAA;AAAA;AAAA,EAIX,eAAe,UAAU,WAAW,QAAO;AACzC,QAAG,SAAS,WAAU;AAAE,aAAO,KAAK,sBAAsB,UAAU,WAAW;AAAA;AAC/E,QAAI,GAAE,SAAS,YAAW;AAC1B,cAAU,KAAK,eAAe,SAAS;AAEvC,WAAO,UAAU,QAAQ;AACzB,aAAQ,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAI;AACrC,WAAK,gBAAgB,SAAS,IAAI,IAAI,WAAW;AACjD,aAAO,UAAU,QAAQ;AAAA;AAAA;AAAA,EAI7B,sBAAsB,UAAU,WAAW,QAAO;AAChD,QAAI,GAAE,WAAW,WAAW,SAAS,YAAW;AAChD,cAAU,KAAK,eAAe,SAAS;AACvC,QAAI,gBAAgB,aAAa,SAAS;AAE1C,aAAQ,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAI;AACtC,UAAI,UAAU,SAAS;AACvB,aAAO,UAAU,QAAQ;AACzB,eAAQ,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAI;AACrC,aAAK,gBAAgB,QAAQ,IAAI,IAAI,eAAe;AACpD,eAAO,UAAU,QAAQ;AAAA;AAAA;AAAA;AAAA,EAK/B,gBAAgB,UAAU,WAAW,QAAO;AAC1C,QAAG,OAAQ,aAAc,UAAS;AAChC,aAAO,UAAU,KAAK,qBAAqB,OAAO,YAAY,UAAU,OAAO;AAAA,eACvE,SAAS,WAAU;AAC3B,WAAK,eAAe,UAAU,WAAW;AAAA,WACpC;AACL,aAAO,UAAU;AAAA;AAAA;AAAA,EAIrB,qBAAqB,YAAY,KAAK,UAAS;AAC7C,QAAI,YAAY,WAAW,QAAQ,SAAS,wBAAwB,OAAO;AAC3E,QAAI,WAAW,SAAS,cAAc;AACtC,aAAS,YAAY,KAAK,kBAAkB,WAAW,YAAY;AACnE,QAAI,YAAY,SAAS;AACzB,QAAI,OAAO,YAAY,CAAC,SAAS,IAAI;AAErC,QAAI,CAAC,eAAe,sBAClB,MAAM,KAAK,UAAU,YAAY,OAAO,CAAC,CAAC,UAAU,gBAAgB,OAAO,MAAM;AAC/E,UAAG,MAAM,aAAa,KAAK,cAAa;AACtC,YAAG,MAAM,aAAa,gBAAe;AACnC,iBAAO,CAAC,UAAU;AAAA;AAEpB,cAAM,aAAa,eAAe;AAClC,YAAG,CAAC,MAAM,IAAG;AAAE,gBAAM,KAAK,GAAG,KAAK,kBAAkB,OAAO;AAAA;AAC3D,YAAG,MAAK;AACN,gBAAM,aAAa,UAAU;AAC7B,gBAAM,YAAY;AAAA;AAEpB,eAAO,CAAC,MAAM;AAAA,aACT;AACL,YAAG,MAAM,UAAU,WAAW,IAAG;AAC/B,mBAAS;AAAA;AAAA,QACE,MAAM,UAAU;AAAA;AAAA;AAAA,GACZ,SAAS,UAAU;AAClC,gBAAM,YAAY,KAAK,WAAW,MAAM,WAAW;AACnD,iBAAO,CAAC,MAAM;AAAA,eACT;AACL,gBAAM;AACN,iBAAO,CAAC,UAAU;AAAA;AAAA;AAAA,OAGrB,CAAC,OAAO;AAEb,QAAG,CAAC,iBAAiB,CAAC,oBAAmB;AACvC,eAAS,4FACP,SAAS,UAAU;AACrB,aAAO,KAAK,WAAW,IAAI,KAAK;AAAA,eACxB,CAAC,iBAAiB,oBAAmB;AAC7C,eAAS,gLACP,SAAS,UAAU;AACrB,aAAO,SAAS;AAAA,WACX;AACL,aAAO,SAAS;AAAA;AAAA;AAAA,EAIpB,WAAW,MAAM,KAAI;AACnB,QAAI,OAAO,SAAS,cAAc;AAClC,SAAK,YAAY;AACjB,SAAK,aAAa,eAAe;AACjC,WAAO;AAAA;AAAA;;;AClPX,IAAI,aAAa;AACjB,qBAA8B;AAAA,SACrB,SAAQ;AAAE,WAAO;AAAA;AAAA,SACjB,UAAU,IAAG;AAAE,WAAO,GAAG;AAAA;AAAA,EAEhC,YAAY,MAAM,IAAI,WAAU;AAC9B,SAAK,SAAS;AACd,SAAK,aAAa,KAAK;AACvB,SAAK,cAAc;AACnB,SAAK,cAAc,IAAI;AACvB,SAAK,mBAAmB;AACxB,SAAK,KAAK;AACV,SAAK,GAAG,YAAY,KAAK,YAAY;AACrC,aAAQ,OAAO,KAAK,aAAY;AAAE,WAAK,OAAO,KAAK,YAAY;AAAA;AAAA;AAAA,EAGjE,YAAW;AAAE,SAAK,WAAW,KAAK;AAAA;AAAA,EAClC,YAAW;AAAE,SAAK,WAAW,KAAK;AAAA;AAAA,EAClC,iBAAgB;AAAE,SAAK,gBAAgB,KAAK;AAAA;AAAA,EAC5C,cAAa;AAAE,SAAK,aAAa,KAAK;AAAA;AAAA,EACtC,gBAAe;AACb,QAAG,KAAK,kBAAiB;AACvB,WAAK,mBAAmB;AACxB,WAAK,eAAe,KAAK;AAAA;AAAA;AAAA,EAG7B,iBAAgB;AACd,SAAK,mBAAmB;AACxB,SAAK,gBAAgB,KAAK;AAAA;AAAA,EAG5B,UAAU,OAAO,UAAU,IAAI,UAAU,WAAW;AAAA,KAAI;AACtD,WAAO,KAAK,OAAO,cAAc,MAAM,OAAO,SAAS;AAAA;AAAA,EAGzD,YAAY,WAAW,OAAO,UAAU,IAAI,UAAU,WAAW;AAAA,KAAI;AACnE,WAAO,KAAK,OAAO,cAAc,WAAW,CAAC,MAAM,cAAc;AAC/D,aAAO,KAAK,cAAc,WAAW,OAAO,SAAS;AAAA;AAAA;AAAA,EAIzD,YAAY,OAAO,UAAS;AAC1B,QAAI,cAAc,CAAC,aAAa,WAAW,SAAS,QAAQ,SAAS,YAAY;AACjF,WAAO,iBAAiB,OAAO,SAAS;AACxC,SAAK,YAAY,IAAI;AACrB,WAAO;AAAA;AAAA,EAGT,kBAAkB,aAAY;AAC5B,QAAI,QAAQ,YAAY,MAAM;AAC9B,WAAO,oBAAoB,OAAO,SAAS;AAC3C,SAAK,YAAY,OAAO;AAAA;AAAA,EAG1B,OAAO,MAAM,OAAM;AACjB,WAAO,KAAK,OAAO,gBAAgB,MAAM;AAAA;AAAA,EAG3C,SAAS,WAAW,MAAM,OAAM;AAC9B,WAAO,KAAK,OAAO,cAAc,WAAW,UAAQ,KAAK,gBAAgB,MAAM;AAAA;AAAA,EAGjF,cAAa;AACX,SAAK,YAAY,QAAQ,iBAAe,KAAK,kBAAkB;AAAA;AAAA;;;AC7DnE,IAAI,KAAK;AAAA,EACP,KAAK,WAAW,UAAU,MAAM,UAAU,UAAS;AACjD,QAAI,CAAC,aAAa,eAAe,YAAY,CAAC,MAAM;AACpD,QAAI,WAAW,SAAS,OAAO,OAAO,MACpC,KAAK,MAAM,YAAY,CAAC,CAAC,aAAa;AAExC,aAAS,QAAQ,CAAC,CAAC,MAAM,UAAU;AACjC,UAAG,SAAS,eAAe,YAAY,MAAK;AAC1C,aAAK,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,YAAY;AAAA;AAEzD,WAAK,YAAY,UAAU,MAAM,QAAQ,QAAM;AAC7C,aAAK,QAAQ,QAAQ,WAAW,UAAU,MAAM,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA,EAKpE,UAAU,IAAG;AACX,WAAO,CAAC,CAAE,IAAG,eAAe,GAAG,gBAAgB,GAAG,iBAAiB,SAAS;AAAA;AAAA,EAO9E,cAAc,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,IAAI,OAAO,QAAQ,WAAS;AAClF,aAAS,UAAU;AACnB,WAAO,aAAa;AACpB,gBAAI,cAAc,IAAI,OAAO,EAAC,QAAQ;AAAA;AAAA,EAGxC,UAAU,WAAW,UAAU,MAAM,UAAU,IAAI,MAAK;AACtD,QAAG,CAAC,KAAK,eAAc;AAAE;AAAA;AAEzB,QAAI,EAAC,OAAO,MAAM,QAAQ,cAAc,SAAS,OAAO,eAAc;AACtE,QAAI,WAAW,EAAC,SAAS,OAAO,QAAQ,cAAc,CAAC,CAAC;AACxD,QAAI,YAAY,cAAc,YAAY,aAAa,aAAa;AACpE,QAAI,YAAY,UAAU,UAAU,aAAa,KAAK,QAAQ,cAAc;AAC5E,SAAK,cAAc,WAAW,CAAC,YAAY,cAAc;AACvD,UAAG,cAAc,UAAS;AACxB,YAAI,EAAC,QAAQ,SAAS,aAAY;AAClC,kBAAU,WAAY,qBAAoB,mBAAmB,SAAS,OAAO;AAC7E,YAAG,SAAQ;AAAE,mBAAS,UAAU;AAAA;AAChC,mBAAW,UAAU,UAAU,WAAW,QAAQ,SAAS,UAAU,UAAU;AAAA,iBACvE,cAAc,UAAS;AAC/B,mBAAW,WAAW,UAAU,WAAW,SAAS,UAAU;AAAA,aACzD;AACL,mBAAW,UAAU,WAAW,UAAU,WAAW,SAAS,UAAU,MAAM;AAAA;AAAA;AAAA;AAAA,EAKpF,eAAe,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,OAAO,YAAY,QAAM;AAChF,SAAK,mBAAmB,IAAI,OAAO,IAAI,YAAY,MAAM;AAAA;AAAA,EAG3D,kBAAkB,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,OAAO,YAAY,QAAM;AACnF,SAAK,mBAAmB,IAAI,IAAI,OAAO,YAAY,MAAM;AAAA;AAAA,EAG3D,gBAAgB,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,MAAM,cAAY;AAC1E,QAAI,CAAC,kBAAkB,SAAS,kBAAkB;AAClD,QAAI,UAAU,MAAM,KAAK,mBAAmB,IAAI,iBAAiB,OAAO,UAAU;AAClF,QAAI,SAAS,MAAM,KAAK,mBAAmB,IAAI,gBAAgB,iBAAiB,OAAO;AACvF,SAAK,WAAW,MAAM,SAAS;AAAA;AAAA,EAGjC,YAAY,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,SAAS,KAAK,MAAM,QAAM;AAC9E,SAAK,OAAO,WAAW,MAAM,IAAI,SAAS,KAAK,MAAM;AAAA;AAAA,EAGvD,UAAU,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,SAAS,YAAY,QAAM;AAC7E,SAAK,KAAK,WAAW,MAAM,IAAI,SAAS,YAAY;AAAA;AAAA,EAGtD,UAAU,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,SAAS,YAAY,QAAM;AAC7E,SAAK,KAAK,WAAW,MAAM,IAAI,SAAS,YAAY;AAAA;AAAA,EAGtD,cAAc,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,MAAM,CAAC,MAAM,QAAM;AACzE,SAAK,iBAAiB,IAAI,CAAC,CAAC,MAAM,OAAO;AAAA;AAAA,EAG3C,iBAAiB,WAAW,UAAU,MAAM,UAAU,IAAI,EAAC,QAAM;AAC/D,SAAK,iBAAiB,IAAI,IAAI,CAAC;AAAA;AAAA,EAKjC,KAAK,WAAW,MAAM,IAAI,SAAS,YAAY,MAAK;AAClD,QAAG,CAAC,KAAK,UAAU,KAAI;AACrB,WAAK,OAAO,WAAW,MAAM,IAAI,SAAS,YAAY,MAAM;AAAA;AAAA;AAAA,EAIhE,KAAK,WAAW,MAAM,IAAI,SAAS,YAAY,MAAK;AAClD,QAAG,KAAK,UAAU,KAAI;AACpB,WAAK,OAAO,WAAW,MAAM,IAAI,SAAS,MAAM,YAAY;AAAA;AAAA;AAAA,EAIhE,OAAO,WAAW,MAAM,IAAI,SAAS,KAAK,MAAM,MAAK;AACnD,QAAI,CAAC,WAAW,gBAAgB,gBAAgB,OAAO,CAAC,IAAI,IAAI;AAChE,QAAI,CAAC,YAAY,iBAAiB,iBAAiB,QAAQ,CAAC,IAAI,IAAI;AACpE,QAAG,UAAU,SAAS,KAAK,WAAW,SAAS,GAAE;AAC/C,UAAG,KAAK,UAAU,KAAI;AACpB,YAAI,UAAU,MAAM;AAClB,eAAK,mBAAmB,IAAI,iBAAiB,UAAU,OAAO,gBAAgB,OAAO;AACrF,iBAAO,sBAAsB,MAAM;AACjC,iBAAK,mBAAmB,IAAI,YAAY;AACxC,mBAAO,sBAAsB,MAAM,KAAK,mBAAmB,IAAI,eAAe;AAAA;AAAA;AAGlF,WAAG,cAAc,IAAI,MAAM;AAC3B,aAAK,WAAW,MAAM,SAAS,MAAM;AACnC,eAAK,mBAAmB,IAAI,IAAI,WAAW,OAAO;AAClD,sBAAI,UAAU,IAAI,UAAU,eAAa,UAAU,MAAM,UAAU;AACnE,aAAG,cAAc,IAAI,MAAM;AAAA;AAAA,aAExB;AACL,YAAG,cAAc,UAAS;AAAE;AAAA;AAC5B,YAAI,UAAU,MAAM;AAClB,eAAK,mBAAmB,IAAI,gBAAgB,WAAW,OAAO,iBAAiB,OAAO;AACtF,sBAAI,UAAU,IAAI,UAAU,eAAa,UAAU,MAAM,UAAW,WAAW;AAC/E,iBAAO,sBAAsB,MAAM;AACjC,iBAAK,mBAAmB,IAAI,WAAW;AACvC,mBAAO,sBAAsB,MAAM,KAAK,mBAAmB,IAAI,cAAc;AAAA;AAAA;AAGjF,WAAG,cAAc,IAAI,MAAM;AAC3B,aAAK,WAAW,MAAM,SAAS,MAAM;AACnC,eAAK,mBAAmB,IAAI,IAAI,UAAU,OAAO;AACjD,aAAG,cAAc,IAAI,MAAM;AAAA;AAAA;AAAA,WAG1B;AACL,UAAG,KAAK,UAAU,KAAI;AACpB,eAAO,sBAAsB,MAAM;AACjC,aAAG,cAAc,IAAI,MAAM;AAC3B,sBAAI,UAAU,IAAI,UAAU,eAAa,UAAU,MAAM,UAAU;AACnE,aAAG,cAAc,IAAI,MAAM;AAAA;AAAA,aAExB;AACL,eAAO,sBAAsB,MAAM;AACjC,aAAG,cAAc,IAAI,MAAM;AAC3B,sBAAI,UAAU,IAAI,UAAU,eAAa,UAAU,MAAM,UAAU,WAAW;AAC9E,aAAG,cAAc,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnC,mBAAmB,IAAI,MAAM,SAAS,YAAY,MAAM,MAAK;AAC3D,QAAI,CAAC,gBAAgB,kBAAkB,kBAAkB,cAAc,CAAC,IAAI,IAAI;AAChF,QAAG,eAAe,SAAS,GAAE;AAC3B,UAAI,UAAU,MAAM,KAAK,mBAAmB,IAAI,iBAAiB,OAAO,iBAAiB;AACzF,UAAI,SAAS,MAAM,KAAK,mBAAmB,IAAI,KAAK,OAAO,iBAAiB,QAAQ,OAAO,gBAAgB,OAAO;AAClH,aAAO,KAAK,WAAW,MAAM,SAAS;AAAA;AAExC,WAAO,sBAAsB,MAAM;AACjC,UAAI,CAAC,UAAU,eAAe,YAAI,UAAU,IAAI,WAAW,CAAC,IAAI;AAChE,UAAI,WAAW,KAAK,OAAO,UAAQ,SAAS,QAAQ,QAAQ,KAAK,CAAC,GAAG,UAAU,SAAS;AACxF,UAAI,cAAc,QAAQ,OAAO,UAAQ,YAAY,QAAQ,QAAQ,KAAK,GAAG,UAAU,SAAS;AAChG,UAAI,UAAU,SAAS,OAAO,UAAQ,QAAQ,QAAQ,QAAQ,GAAG,OAAO;AACxE,UAAI,aAAa,YAAY,OAAO,UAAQ,KAAK,QAAQ,QAAQ,GAAG,OAAO;AAE3E,kBAAI,UAAU,IAAI,WAAW,eAAa;AACxC,kBAAU,UAAU,OAAO,GAAG;AAC9B,kBAAU,UAAU,IAAI,GAAG;AAC3B,eAAO,CAAC,SAAS;AAAA;AAAA;AAAA;AAAA,EAKvB,iBAAiB,IAAI,MAAM,SAAQ;AACjC,QAAI,CAAC,UAAU,eAAe,YAAI,UAAU,IAAI,SAAS,CAAC,IAAI;AAE9D,QAAI,eAAe,KAAK,IAAI,CAAC,CAAC,MAAM,UAAU,MAAM,OAAO;AAC3D,QAAI,UAAU,SAAS,OAAO,CAAC,CAAC,MAAM,UAAU,CAAC,aAAa,SAAS,OAAO,OAAO;AACrF,QAAI,aAAa,YAAY,OAAO,CAAC,SAAS,CAAC,aAAa,SAAS,OAAO,OAAO;AAEnF,gBAAI,UAAU,IAAI,SAAS,eAAa;AACtC,iBAAW,QAAQ,UAAQ,UAAU,gBAAgB;AACrD,cAAQ,QAAQ,CAAC,CAAC,MAAM,SAAS,UAAU,aAAa,MAAM;AAC9D,aAAO,CAAC,SAAS;AAAA;AAAA;AAAA,EAIrB,cAAc,IAAI,SAAQ;AAAE,WAAO,QAAQ,MAAM,UAAQ,GAAG,UAAU,SAAS;AAAA;AAAA,EAE/E,aAAa,IAAI,YAAW;AAC1B,WAAO,CAAC,KAAK,UAAU,OAAO,KAAK,cAAc,IAAI;AAAA;AAAA,EAGvD,YAAY,UAAU,EAAC,MAAI;AACzB,WAAO,KAAK,YAAI,IAAI,UAAU,MAAM,CAAC;AAAA;AAAA;AAIzC,IAAO,aAAQ;;;ACpJf,IAAI,gBAAgB,CAAC,MAAM,MAAM,YAAY,OAAO;AAClD,MAAI,WAAW,IAAI,SAAS;AAC5B,MAAI,WAAW;AAEf,WAAS,QAAQ,CAAC,KAAK,KAAK,WAAW;AACrC,QAAG,eAAe,MAAK;AAAE,eAAS,KAAK;AAAA;AAAA;AAIzC,WAAS,QAAQ,SAAO,SAAS,OAAO;AAExC,MAAI,SAAS,IAAI;AACjB,WAAQ,CAAC,KAAK,QAAQ,SAAS,WAAU;AACvC,QAAG,UAAU,WAAW,KAAK,UAAU,QAAQ,QAAQ,GAAE;AACvD,aAAO,OAAO,KAAK;AAAA;AAAA;AAGvB,WAAQ,WAAW,MAAK;AAAE,WAAO,OAAO,SAAS,KAAK;AAAA;AAEtD,SAAO,OAAO;AAAA;AAGhB,iBAA0B;AAAA,EACxB,YAAY,IAAI,YAAY,YAAY,OAAM;AAC5C,SAAK,aAAa;AAClB,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,OAAO,aAAa,WAAW,OAAO;AAC3C,SAAK,KAAK;AACV,SAAK,KAAK,KAAK,GAAG;AAClB,SAAK,MAAM;AACX,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,YAAY,KAAK,SAAS,KAAK,OAAO,YAAY,IAAI;AAC3D,SAAK,cAAc;AACnB,SAAK,YAAY;AACjB,SAAK,eAAe,SAAS,QAAO;AAAE,gBAAU;AAAA;AAChD,SAAK,eAAe,WAAU;AAAA;AAC9B,SAAK,iBAAiB,KAAK,SAAS,OAAO;AAC3C,SAAK,YAAY;AACjB,SAAK,YAAY;AACjB,SAAK,cAAc;AACnB,SAAK,WAAW,KAAK,SAAS,OAAO;AACrC,SAAK,KAAK,SAAS,KAAK,MAAM;AAC9B,SAAK,UAAU,KAAK,WAAW,QAAQ,MAAM,KAAK,MAAM,MAAM;AAC5D,aAAO;AAAA,QACL,UAAU,KAAK,WAAW,KAAK,OAAO;AAAA,QACtC,KAAK,KAAK,WAAW,SAAY,KAAK,QAAQ;AAAA,QAC9C,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,QACd,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA;AAAA;AAGhB,SAAK,WAAW,KAAK,WAAW;AAChC,SAAK;AAAA;AAAA,EAGP,QAAQ,MAAK;AAAE,SAAK,OAAO;AAAA;AAAA,EAE3B,YAAY,MAAK;AACf,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA;AAAA,EAGd,SAAQ;AAAE,WAAO,KAAK,GAAG,aAAa;AAAA;AAAA,EAEtC,gBAAe;AACb,QAAI,SAAS,KAAK,WAAW,OAAO,KAAK;AACzC,QAAI,WACF,YAAI,IAAI,UAAU,IAAI,KAAK,QAAQ,sBAChC,IAAI,UAAQ,KAAK,OAAO,KAAK,MAAM,OAAO,SAAO,OAAQ,QAAS;AAEvE,QAAG,SAAS,SAAS,GAAE;AAAE,aAAO,mBAAmB;AAAA;AACnD,WAAO,aAAa,KAAK;AAEzB,WAAO;AAAA;AAAA,EAGT,cAAa;AAAE,WAAO,KAAK,QAAQ;AAAA;AAAA,EAEnC,aAAY;AAAE,WAAO,KAAK,GAAG,aAAa;AAAA;AAAA,EAE1C,YAAW;AACT,QAAI,MAAM,KAAK,GAAG,aAAa;AAC/B,WAAO,QAAQ,KAAK,OAAO;AAAA;AAAA,EAG7B,QAAQ,WAAW,WAAW;AAAA,KAAI;AAChC,SAAK;AACL,SAAK,YAAY;AACjB,WAAO,KAAK,KAAK,SAAS,KAAK;AAC/B,QAAG,KAAK,QAAO;AAAE,aAAO,KAAK,KAAK,SAAS,KAAK,OAAO,IAAI,KAAK;AAAA;AAChE,iBAAa,KAAK;AAClB,QAAI,aAAa,MAAM;AACrB;AACA,eAAQ,MAAM,KAAK,WAAU;AAC3B,aAAK,YAAY,KAAK,UAAU;AAAA;AAAA;AAIpC,gBAAI,sBAAsB,KAAK;AAE/B,SAAK,IAAI,aAAa,MAAM,CAAC;AAC7B,SAAK,QAAQ,QACV,QAAQ,MAAM,YACd,QAAQ,SAAS,YACjB,QAAQ,WAAW;AAAA;AAAA,EAGxB,uBAAuB,SAAQ;AAC7B,SAAK,GAAG,UAAU,OAChB,qBACA,wBACA;AAEF,SAAK,GAAG,UAAU,IAAI,GAAG;AAAA;AAAA,EAG3B,WAAW,SAAQ;AACjB,iBAAa,KAAK;AAClB,QAAG,SAAQ;AACT,WAAK,cAAc,WAAW,MAAM,KAAK,cAAc;AAAA,WAClD;AACL,eAAQ,MAAM,KAAK,WAAU;AAAE,aAAK,UAAU,IAAI;AAAA;AAClD,WAAK,oBAAoB;AAAA;AAAA;AAAA,EAI7B,aAAY;AACV,iBAAa,KAAK;AAClB,SAAK,oBAAoB;AAAA;AAAA,EAG3B,qBAAoB;AAClB,aAAQ,MAAM,KAAK,WAAU;AAAE,WAAK,UAAU,IAAI;AAAA;AAAA;AAAA,EAGpD,IAAI,MAAM,aAAY;AACpB,SAAK,WAAW,IAAI,MAAM,MAAM;AAAA;AAAA,EAGlC,WAAW,MAAM,SAAS,SAAS,WAAU;AAAA,KAAG;AAC9C,SAAK,WAAW,WAAW,MAAM,SAAS;AAAA;AAAA,EAG5C,cAAc,WAAW,UAAS;AAChC,QAAG,qBAAqB,eAAe,qBAAqB,YAAW;AACrE,aAAO,KAAK,WAAW,MAAM,WAAW,UAAQ,SAAS,MAAM;AAAA;AAGjE,QAAG,MAAM,YAAW;AAClB,UAAI,UAAU,YAAI,sBAAsB,KAAK,IAAI;AACjD,UAAG,QAAQ,WAAW,GAAE;AACtB,iBAAS,6CAA6C;AAAA,aACjD;AACL,iBAAS,MAAM,SAAS;AAAA;AAAA,WAErB;AACL,UAAI,UAAU,MAAM,KAAK,SAAS,iBAAiB;AACnD,UAAG,QAAQ,WAAW,GAAE;AAAE,iBAAS,mDAAmD;AAAA;AACtF,cAAQ,QAAQ,YAAU,KAAK,WAAW,MAAM,QAAQ,UAAQ,SAAS,MAAM;AAAA;AAAA;AAAA,EAInF,UAAU,MAAM,SAAS,UAAS;AAChC,SAAK,IAAI,MAAM,MAAM,CAAC,IAAI,MAAM;AAChC,QAAI,EAAC,MAAM,OAAO,QAAQ,UAAS,SAAS,QAAQ;AACpD,QAAG,OAAM;AAAE,kBAAI,SAAS;AAAA;AAExB,aAAS,EAAC,MAAM,OAAO;AACvB,WAAO;AAAA;AAAA,EAGT,OAAO,MAAK;AACV,QAAI,EAAC,UAAU,cAAa;AAC5B,QAAG,WAAU;AACX,UAAI,CAAC,KAAK,SAAS;AACnB,WAAK,KAAK,YAAI,qBAAqB,KAAK,IAAI,KAAK;AAAA;AAEnD,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,QAAQ;AAEb,oBAAQ,UAAU,KAAK,WAAW,cAAc,OAAO,SAAS,UAAU;AAC1E,SAAK,UAAU,SAAS,UAAU,CAAC,EAAC,MAAM,aAAY;AACpD,WAAK,WAAW,IAAI,SAAS,KAAK,IAAI;AACtC,UAAI,OAAO,KAAK,gBAAgB,MAAM;AACtC,WAAK;AACL,UAAI,QAAQ,KAAK,iBAAiB;AAClC,WAAK;AAEL,UAAG,MAAM,SAAS,GAAE;AAClB,cAAM,QAAQ,CAAC,CAAC,MAAM,SAAS,SAAS,MAAM;AAC5C,eAAK,iBAAiB,MAAM,QAAQ,WAAQ;AAC1C,gBAAG,MAAM,MAAM,SAAS,GAAE;AACxB,mBAAK,eAAe,OAAM,MAAM;AAAA;AAAA;AAAA;AAAA,aAIjC;AACL,aAAK,eAAe,MAAM,MAAM;AAAA;AAAA;AAAA;AAAA,EAKtC,kBAAiB;AACf,gBAAI,IAAI,UAAU,IAAI,gBAAgB,KAAK,QAAQ,YAAY,QAAM;AACnE,SAAG,gBAAgB;AACnB,SAAG,gBAAgB;AAAA;AAAA;AAAA,EAIvB,eAAe,EAAC,cAAa,MAAM,QAAO;AAGxC,QAAG,KAAK,YAAY,KAAM,KAAK,UAAU,CAAC,KAAK,OAAO,iBAAiB;AACrE,aAAO,KAAK,eAAe,YAAY,MAAM;AAAA;AAO/C,QAAI,cAAc,YAAI,0BAA0B,MAAM,KAAK,IAAI,OAAO,UAAQ;AAC5E,UAAI,SAAS,KAAK,MAAM,KAAK,GAAG,cAAc,QAAQ,KAAK;AAC3D,UAAI,YAAY,UAAU,OAAO,aAAa;AAC9C,UAAG,WAAU;AAAE,aAAK,aAAa,YAAY;AAAA;AAC7C,aAAO,KAAK,UAAU;AAAA;AAGxB,QAAG,YAAY,WAAW,GAAE;AAC1B,UAAG,KAAK,QAAO;AACb,aAAK,KAAK,eAAe,KAAK,CAAC,MAAM,MAAM,KAAK,eAAe,YAAY,MAAM;AACjF,aAAK,OAAO,QAAQ;AAAA,aACf;AACL,aAAK;AACL,aAAK,eAAe,YAAY,MAAM;AAAA;AAAA,WAEnC;AACL,WAAK,KAAK,eAAe,KAAK,CAAC,MAAM,MAAM,KAAK,eAAe,YAAY,MAAM;AAAA;AAAA;AAAA,EAIrF,kBAAiB;AACf,SAAK,KAAK,YAAI,KAAK,KAAK;AACxB,SAAK,GAAG,aAAa,aAAa,KAAK,KAAK;AAAA;AAAA,EAG9C,eAAe,YAAY,MAAM,QAAO;AACtC,SAAK;AACL,QAAI,QAAQ,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM;AACvD,UAAM;AACN,SAAK,aAAa,OAAO;AACzB,SAAK;AACL,gBAAI,IAAI,KAAK,IAAI,IAAI,KAAK,QAAQ,yBAAyB,aAAa,YAAU;AAChF,UAAI,OAAO,KAAK,QAAQ;AACxB,UAAG,MAAK;AAAE,aAAK;AAAA;AAAA;AAGjB,SAAK,cAAc;AACnB,SAAK,WAAW,eAAe;AAC/B,SAAK;AAEL,QAAG,YAAW;AACZ,UAAI,EAAC,MAAM,OAAM;AACjB,WAAK,WAAW,aAAa,IAAI;AAAA;AAEnC,SAAK;AACL,QAAG,KAAK,YAAY,GAAE;AAAE,WAAK;AAAA;AAC7B,SAAK;AAAA;AAAA,EAGP,wBAAwB,QAAQ,MAAK;AACnC,SAAK,WAAW,WAAW,qBAAqB,CAAC,QAAQ;AACzD,QAAI,OAAO,KAAK,QAAQ;AACxB,QAAI,YAAY,QAAQ,YAAI,UAAU,QAAQ,KAAK,QAAQ;AAC3D,QAAG,QAAQ,CAAC,OAAO,YAAY,SAAS,CAAE,cAAa,WAAW,OAAO,SAAS,KAAK,WAAU;AAC/F,WAAK;AACL,aAAO;AAAA;AAAA;AAAA,EAIX,aAAa,OAAO,WAAU;AAC5B,QAAI,aAAa;AACjB,QAAI,mBAAmB;AACvB,QAAI,iBAAiB,IAAI;AAEzB,UAAM,MAAM,SAAS,QAAM;AACzB,WAAK,WAAW,WAAW,eAAe,CAAC;AAE3C,UAAI,UAAU,KAAK,QAAQ;AAC3B,UAAG,SAAQ;AAAE,gBAAQ;AAAA;AAAA;AAGvB,UAAM,MAAM,iBAAiB,QAAM;AACjC,UAAG,YAAI,YAAY,KAAI;AACrB,aAAK,WAAW;AAAA,aACX;AACL,2BAAmB;AAAA;AAAA;AAIvB,UAAM,OAAO,WAAW,CAAC,QAAQ,SAAS;AACxC,UAAI,OAAO,KAAK,wBAAwB,QAAQ;AAChD,UAAG,MAAK;AAAE,uBAAe,IAAI,OAAO;AAAA;AAAA;AAGtC,UAAM,MAAM,WAAW,QAAM;AAC3B,UAAG,eAAe,IAAI,GAAG,KAAI;AAAE,aAAK,QAAQ,IAAI;AAAA;AAAA;AAGlD,UAAM,MAAM,aAAa,CAAC,OAAO;AAC/B,UAAG,GAAG,aAAa,KAAK,cAAa;AAAE,mBAAW,KAAK;AAAA;AAAA;AAGzD,UAAM,MAAM,wBAAwB,SAAO,KAAK,qBAAqB,KAAK;AAC1E,UAAM;AACN,SAAK,qBAAqB,YAAY;AAEtC,WAAO;AAAA;AAAA,EAGT,qBAAqB,UAAU,WAAU;AACvC,QAAI,gBAAgB;AACpB,aAAS,QAAQ,YAAU;AACzB,UAAI,aAAa,YAAI,IAAI,QAAQ,IAAI;AACrC,UAAI,QAAQ,YAAI,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAC7C,iBAAW,OAAO,QAAQ,QAAQ,QAAM;AACtC,YAAI,MAAM,KAAK,YAAY;AAC3B,YAAG,MAAM,QAAQ,cAAc,QAAQ,SAAS,IAAG;AAAE,wBAAc,KAAK;AAAA;AAAA;AAE1E,YAAM,OAAO,QAAQ,QAAQ,YAAU;AACrC,YAAI,OAAO,KAAK,QAAQ;AACxB,gBAAQ,KAAK,YAAY;AAAA;AAAA;AAM7B,QAAG,WAAU;AACX,WAAK,6BAA6B;AAAA;AAAA;AAAA,EAItC,kBAAiB;AACf,gBAAI,gBAAgB,KAAK,IAAI,KAAK,IAAI,QAAQ,QAAM,KAAK,UAAU;AAAA;AAAA,EAGrE,aAAa,IAAG;AAAE,WAAO,KAAK,KAAK,SAAS,KAAK,IAAI;AAAA;AAAA,EAErD,kBAAkB,IAAG;AACnB,QAAG,GAAG,OAAO,KAAK,IAAG;AACnB,aAAO;AAAA,WACF;AACL,aAAO,KAAK,SAAS,GAAG,aAAa,gBAAgB,GAAG;AAAA;AAAA;AAAA,EAI5D,kBAAkB,IAAG;AACnB,aAAQ,YAAY,KAAK,KAAK,UAAS;AACrC,eAAQ,WAAW,KAAK,KAAK,SAAS,WAAU;AAC9C,YAAG,YAAY,IAAG;AAAE,iBAAO,KAAK,KAAK,SAAS,UAAU,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKvE,UAAU,IAAG;AACX,QAAI,QAAQ,KAAK,aAAa,GAAG;AACjC,QAAG,CAAC,OAAM;AACR,UAAI,OAAO,IAAI,KAAK,IAAI,KAAK,YAAY;AACzC,WAAK,KAAK,SAAS,KAAK,IAAI,KAAK,MAAM;AACvC,WAAK;AACL,WAAK;AACL,aAAO;AAAA;AAAA;AAAA,EAIX,gBAAe;AAAE,WAAO,KAAK;AAAA;AAAA,EAE7B,QAAQ,QAAO;AACb,SAAK;AAEL,QAAG,KAAK,eAAe,GAAE;AACvB,UAAG,KAAK,QAAO;AACb,aAAK,OAAO,QAAQ;AAAA,aACf;AACL,aAAK;AAAA;AAAA;AAAA;AAAA,EAKX,0BAAyB;AACvB,SAAK,aAAa,MAAM;AACtB,WAAK,eAAe,QAAQ,CAAC,CAAC,MAAM,QAAQ;AAC1C,YAAG,CAAC,KAAK,eAAc;AAAE;AAAA;AAAA;AAE3B,WAAK,iBAAiB;AAAA;AAAA;AAAA,EAI1B,OAAO,MAAM,QAAO;AAClB,QAAG,KAAK,mBAAoB,KAAK,WAAW,oBAAoB,CAAC,YAAI,YAAY,KAAK,KAAK;AACzF,aAAO,KAAK,aAAa,KAAK,EAAC,MAAM;AAAA;AAGvC,SAAK,SAAS,UAAU;AACxB,QAAI,mBAAmB;AAKvB,QAAG,KAAK,SAAS,oBAAoB,OAAM;AACzC,WAAK,WAAW,KAAK,4BAA4B,MAAM;AACrD,YAAI,aAAa,YAAI,eAAe,KAAK,IAAI,KAAK,SAAS,cAAc;AACzE,mBAAW,QAAQ,eAAa;AAC9B,cAAG,KAAK,eAAe,KAAK,SAAS,aAAa,MAAM,YAAY,YAAW;AAAE,+BAAmB;AAAA;AAAA;AAAA;AAAA,eAGhG,CAAC,QAAQ,OAAM;AACvB,WAAK,WAAW,KAAK,uBAAuB,MAAM;AAChD,YAAI,OAAO,KAAK,gBAAgB,MAAM;AACtC,YAAI,QAAQ,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM;AACvD,2BAAmB,KAAK,aAAa,OAAO;AAAA;AAAA;AAIhD,SAAK,WAAW,eAAe;AAC/B,QAAG,kBAAiB;AAAE,WAAK;AAAA;AAAA;AAAA,EAG7B,gBAAgB,MAAM,MAAK;AACzB,WAAO,KAAK,WAAW,KAAK,kBAAkB,SAAS,MAAM;AAC3D,UAAI,MAAM,KAAK,GAAG;AAGlB,UAAI,OAAO,OAAO,KAAK,SAAS,cAAc,MAAM,OAAO,KAAK,eAAe;AAC/E,UAAI,OAAO,KAAK,SAAS,SAAS;AAClC,aAAO,IAAI,OAAO,SAAS;AAAA;AAAA;AAAA,EAI/B,eAAe,MAAM,KAAI;AACvB,QAAG,QAAQ;AAAO,aAAO;AACzB,QAAI,OAAO,KAAK,SAAS,kBAAkB;AAC3C,QAAI,QAAQ,IAAI,SAAS,MAAM,KAAK,IAAI,KAAK,IAAI,MAAM;AACvD,QAAI,gBAAgB,KAAK,aAAa,OAAO;AAC7C,WAAO;AAAA;AAAA,EAGT,QAAQ,IAAG;AAAE,WAAO,KAAK,UAAU,SAAS,UAAU;AAAA;AAAA,EAEtD,QAAQ,IAAG;AACT,QAAG,SAAS,UAAU,OAAO,CAAC,GAAG,cAAa;AAAE;AAAA;AAChD,QAAI,WAAW,GAAG,aAAa,YAAY,eAAe,GAAG,aAAa,KAAK,QAAQ;AACvF,QAAG,YAAY,CAAC,KAAK,YAAY,KAAI;AAAE;AAAA;AACvC,QAAI,YAAY,KAAK,WAAW,iBAAiB;AAEjD,QAAG,WAAU;AACX,UAAG,CAAC,GAAG,IAAG;AAAE,iBAAS,uBAAuB,yDAAyD;AAAA;AACrG,UAAI,OAAO,IAAI,SAAS,MAAM,IAAI;AAClC,WAAK,UAAU,SAAS,UAAU,KAAK,OAAO;AAC9C,aAAO;AAAA,eACC,aAAa,MAAK;AAC1B,eAAS,2BAA2B,aAAa;AAAA;AAAA;AAAA,EAIrD,YAAY,MAAK;AACf,SAAK;AACL,SAAK;AACL,WAAO,KAAK,UAAU,SAAS,UAAU,KAAK;AAAA;AAAA,EAGhD,sBAAqB;AACnB,SAAK,aAAa,QAAQ,CAAC,EAAC,MAAM,aAAY,KAAK,OAAO,MAAM;AAChE,SAAK,eAAe;AAAA;AAAA,EAGtB,UAAU,OAAO,IAAG;AAClB,SAAK,WAAW,UAAU,KAAK,SAAS,OAAO,UAAQ;AACrD,UAAG,KAAK,iBAAgB;AACtB,aAAK,KAAK,eAAe,KAAK,CAAC,MAAM,MAAM,GAAG;AAAA,aACzC;AACL,aAAK,WAAW,iBAAiB,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA,EAKhD,cAAa;AAGX,SAAK,WAAW,UAAU,KAAK,SAAS,QAAQ,CAAC,YAAY;AAC3D,WAAK,WAAW,iBAAiB,MAAM;AACrC,aAAK,UAAU,UAAU,SAAS,CAAC,EAAC,MAAM,aAAY,KAAK,OAAO,MAAM;AAAA;AAAA;AAG5E,SAAK,UAAU,YAAY,CAAC,EAAC,IAAI,YAAW,KAAK,WAAW,EAAC,IAAI;AACjE,SAAK,UAAU,cAAc,CAAC,UAAU,KAAK,YAAY;AACzD,SAAK,UAAU,iBAAiB,CAAC,UAAU,KAAK,eAAe;AAC/D,SAAK,QAAQ,QAAQ,YAAU,KAAK,QAAQ;AAC5C,SAAK,QAAQ,QAAQ,YAAU,KAAK,QAAQ;AAAA;AAAA,EAG9C,qBAAoB;AAClB,aAAQ,MAAM,KAAK,KAAK,SAAS,KAAK,KAAI;AACxC,WAAK,aAAa,IAAI;AAAA;AAAA;AAAA,EAI1B,eAAe,OAAM;AACnB,QAAI,EAAC,IAAI,MAAM,UAAS;AACxB,QAAI,MAAM,KAAK,UAAU;AACzB,SAAK,WAAW,gBAAgB,KAAK,MAAM;AAAA;AAAA,EAG7C,YAAY,OAAM;AAChB,QAAI,EAAC,IAAI,SAAQ;AACjB,SAAK,OAAO,KAAK,UAAU;AAC3B,SAAK,WAAW,aAAa,IAAI;AAAA;AAAA,EAGnC,UAAU,IAAG;AACX,WAAO,GAAG,WAAW,OAAO,GAAG,OAAO,SAAS,aAAa,OAAO,SAAS,OAAO,OAAO;AAAA;AAAA,EAG5F,WAAW,EAAC,IAAI,SAAO;AAAE,SAAK,WAAW,SAAS,IAAI;AAAA;AAAA,EAEtD,cAAa;AAAE,WAAO,KAAK;AAAA;AAAA,EAE3B,KAAK,UAAS;AACZ,QAAG,KAAK,UAAS;AACf,WAAK,eAAe,KAAK,WAAW,gBAAgB,EAAC,IAAI,KAAK,MAAM,MAAM;AAAA;AAE5E,SAAK,eAAe,CAAC,WAAW;AAC9B,eAAS,UAAU,WAAU;AAAA;AAC7B,iBAAW,SAAS,KAAK,WAAW,UAAU;AAAA;AAEhD,SAAK,WAAW,SAAS,MAAM,EAAC,SAAS,SAAQ,MAAM;AACrD,aAAO,KAAK,QAAQ,OACjB,QAAQ,MAAM,UAAQ;AACrB,YAAG,CAAC,KAAK,eAAc;AACrB,eAAK,WAAW,iBAAiB,MAAM,KAAK,OAAO;AAAA;AAAA,SAGtD,QAAQ,SAAS,UAAQ,CAAC,KAAK,iBAAiB,KAAK,YAAY,OACjE,QAAQ,WAAW,MAAM,CAAC,KAAK,iBAAiB,KAAK,YAAY,EAAC,QAAQ;AAAA;AAAA;AAAA,EAIjF,YAAY,MAAK;AACf,QAAG,KAAK,WAAW,kBAAkB,KAAK,WAAW,SAAQ;AAC3D,WAAK,IAAI,SAAS,MAAM,CAAC,4DAA4D;AACrF,aAAO,KAAK,WAAW,EAAC,IAAI,KAAK;AAAA;AAEnC,QAAG,KAAK,YAAY,KAAK,eAAc;AACrC,WAAK,cAAc;AACnB,WAAK,QAAQ;AAAA;AAEf,QAAG,KAAK,UAAS;AAAE,aAAO,KAAK,WAAW,KAAK;AAAA;AAC/C,QAAG,KAAK,eAAc;AAAE,aAAO,KAAK,eAAe,KAAK;AAAA;AACxD,SAAK,IAAI,SAAS,MAAM,CAAC,kBAAkB;AAC3C,QAAG,KAAK,WAAW,eAAc;AAAE,WAAK,WAAW,iBAAiB;AAAA;AAAA;AAAA,EAGtE,QAAQ,QAAO;AACb,QAAG,KAAK,eAAc;AAAE;AAAA;AACxB,QAAG,KAAK,WAAW,oBAAoB,WAAW,SAAQ;AACxD,aAAO,KAAK,WAAW,iBAAiB;AAAA;AAE1C,SAAK;AACL,SAAK,WAAW,kBAAkB;AAElC,QAAG,SAAS,eAAc;AAAE,eAAS,cAAc;AAAA;AACnD,QAAG,KAAK,WAAW,cAAa;AAC9B,WAAK,WAAW;AAAA;AAAA;AAAA,EAIpB,QAAQ,QAAO;AACb,SAAK,QAAQ;AACb,QAAG,KAAK,WAAW,eAAc;AAAE,WAAK,IAAI,SAAS,MAAM,CAAC,gBAAgB;AAAA;AAC5E,QAAG,CAAC,KAAK,WAAW,cAAa;AAAE,WAAK;AAAA;AAAA;AAAA,EAG1C,eAAc;AACZ,QAAG,KAAK,UAAS;AAAE,kBAAI,cAAc,QAAQ,0BAA0B,EAAC,QAAQ,EAAC,IAAI,KAAK,MAAM,MAAM;AAAA;AACtG,SAAK;AACL,SAAK,oBAAoB,wBAAwB;AAAA;AAAA,EAGnD,cAAc,cAAc,OAAO,SAAS,UAAU,WAAW;AAAA,KAAI;AACnE,QAAG,CAAC,KAAK,eAAc;AAAE;AAAA;AAEzB,QAAI,CAAC,KAAK,CAAC,KAAK,QAAQ,eAAe,iBAAiB,CAAC,MAAM,IAAI;AACnE,QAAI,gBAAgB,WAAU;AAAA;AAC9B,QAAG,KAAK,gBAAiB,MAAO,GAAG,aAAa,KAAK,QAAQ,uBAAuB,MAAO;AACzF,sBAAgB,KAAK,WAAW,gBAAgB,EAAC,MAAM,WAAW,QAAQ;AAAA;AAG5E,QAAG,OAAQ,QAAQ,QAAS,UAAS;AAAE,aAAO,QAAQ;AAAA;AACtD,WACE,KAAK,WAAW,SAAS,MAAM,EAAC,SAAS,QAAO,MAAM;AACpD,aAAO,KAAK,QAAQ,KAAK,OAAO,SAAS,cAAc,QAAQ,MAAM,UAAQ;AAC3E,YAAG,QAAQ,MAAK;AAAE,eAAK,SAAS;AAAA;AAChC,YAAI,SAAS,CAAC,cAAc;AAC1B,cAAG,KAAK,UAAS;AAAE,iBAAK,WAAW,KAAK;AAAA;AACxC,cAAG,KAAK,YAAW;AAAE,iBAAK,YAAY,KAAK;AAAA;AAC3C,cAAG,KAAK,eAAc;AAAE,iBAAK,eAAe,KAAK;AAAA;AACjD;AACA,kBAAQ,MAAM;AAAA;AAEhB,YAAG,KAAK,MAAK;AACX,eAAK,WAAW,iBAAiB,MAAM;AACrC,gBAAI,YAAY,KAAK,UAAU,UAAU,KAAK,MAAM,CAAC,EAAC,MAAM,aAAY;AACtE,mBAAK,OAAO,MAAM;AAAA;AAEpB,mBAAO;AAAA;AAAA,eAEJ;AACL,iBAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,SAAS,KAAI;AACX,gBAAI,IAAI,UAAU,IAAI,gBAAgB,KAAK,QAAQ,YAAY,SAAS,QAAM;AAC5E,UAAI,cAAc,GAAG,aAAa;AAElC,SAAG,gBAAgB;AACnB,SAAG,gBAAgB;AAEnB,UAAG,GAAG,aAAa,kBAAkB,MAAK;AACxC,WAAG,WAAW;AACd,WAAG,gBAAgB;AAAA;AAErB,UAAG,gBAAgB,MAAK;AACtB,WAAG,WAAW,gBAAgB,SAAS,OAAO;AAC9C,WAAG,gBAAgB;AAAA;AAGrB,wBAAkB,QAAQ,eAAa,YAAI,YAAY,IAAI;AAE3D,UAAI,iBAAiB,GAAG,aAAa;AACrC,UAAG,mBAAmB,MAAK;AACzB,WAAG,YAAY;AACf,WAAG,gBAAgB;AAAA;AAErB,UAAI,OAAO,YAAI,QAAQ,IAAI;AAC3B,UAAG,MAAK;AACN,YAAI,OAAO,KAAK,wBAAwB,IAAI;AAC5C,iBAAS,QAAQ,IAAI,MAAM,KAAK,WAAW;AAC3C,YAAG,MAAK;AAAE,eAAK;AAAA;AACf,oBAAI,cAAc,IAAI;AAAA;AAAA;AAAA;AAAA,EAK5B,OAAO,UAAU,OAAO,OAAO,IAAG;AAChC,QAAI,SAAS,KAAK;AAClB,QAAI,cAAc,KAAK,QAAQ;AAC/B,QAAG,KAAK,SAAQ;AAAE,iBAAW,SAAS,OAAO,YAAI,IAAI,UAAU,KAAK;AAAA;AAEpE,aAAS,QAAQ,QAAM;AACrB,SAAG,UAAU,IAAI,OAAO;AACxB,SAAG,aAAa,SAAS;AACzB,SAAG,aAAa,aAAa,KAAK,GAAG;AACrC,UAAI,cAAc,GAAG,aAAa;AAClC,UAAG,gBAAgB,MAAK;AACtB,YAAG,CAAC,GAAG,aAAa,2BAA0B;AAC5C,aAAG,aAAa,0BAA0B,GAAG;AAAA;AAE/C,YAAG,gBAAgB,IAAG;AAAE,aAAG,YAAY;AAAA;AACvC,WAAG,aAAa,YAAY;AAAA;AAAA;AAGhC,WAAO,CAAC,QAAQ,UAAU;AAAA;AAAA,EAG5B,YAAY,IAAG;AACb,QAAI,MAAM,GAAG,gBAAgB,GAAG,aAAa;AAC7C,WAAO,MAAM,SAAS,OAAO;AAAA;AAAA,EAG/B,kBAAkB,QAAQ,WAAW,OAAO,IAAG;AAC7C,QAAG,MAAM,YAAW;AAAE,aAAO;AAAA;AAE7B,QAAI,gBAAgB,OAAO,aAAa,KAAK,QAAQ;AACrD,QAAG,MAAM,gBAAe;AACtB,aAAO,SAAS;AAAA,eACR,aAAc,mBAAkB,QAAQ,KAAK,SAAQ;AAC7D,aAAO,KAAK,mBAAmB;AAAA,WAC1B;AACL,aAAO;AAAA;AAAA;AAAA,EAIX,mBAAmB,WAAU;AAC3B,QAAG,MAAM,YAAW;AAClB,aAAO;AAAA,eACC,WAAU;AAClB,aAAO,MAAM,UAAU,QAAQ,IAAI,mBAAmB,QAAM,KAAK,YAAY,OAAO,KAAK,YAAY;AAAA,WAChG;AACL,aAAO;AAAA;AAAA;AAAA,EAIX,cAAc,WAAW,OAAO,SAAS,SAAQ;AAC/C,QAAG,CAAC,KAAK,eAAc;AACrB,WAAK,IAAI,QAAQ,MAAM,CAAC,qDAAqD,OAAO;AACpF,aAAO;AAAA;AAET,QAAI,CAAC,KAAK,KAAK,QAAQ,KAAK,OAAO,IAAI;AACvC,SAAK,cAAc,MAAM,CAAC,KAAK,KAAK,OAAO,SAAS;AAAA,MAClD,MAAM;AAAA,MACN;AAAA,MACA,OAAO;AAAA,MACP,KAAK,KAAK,mBAAmB;AAAA,OAC5B,CAAC,MAAM,UAAU,QAAQ,OAAO;AAEnC,WAAO;AAAA;AAAA,EAGT,YAAY,IAAI,MAAM,OAAM;AAC1B,QAAI,SAAS,KAAK,QAAQ;AAC1B,aAAQ,IAAI,GAAG,IAAI,GAAG,WAAW,QAAQ,KAAI;AAC3C,UAAG,CAAC,MAAK;AAAE,eAAO;AAAA;AAClB,UAAI,OAAO,GAAG,WAAW,GAAG;AAC5B,UAAG,KAAK,WAAW,SAAQ;AAAE,aAAK,KAAK,QAAQ,QAAQ,OAAO,GAAG,aAAa;AAAA;AAAA;AAEhF,QAAG,GAAG,UAAU,QAAU;AACxB,UAAG,CAAC,MAAK;AAAE,eAAO;AAAA;AAClB,WAAK,QAAQ,GAAG;AAEhB,UAAG,GAAG,YAAY,WAAW,iBAAiB,QAAQ,GAAG,SAAS,KAAK,CAAC,GAAG,SAAQ;AACjF,eAAO,KAAK;AAAA;AAAA;AAGhB,QAAG,OAAM;AACP,UAAG,CAAC,MAAK;AAAE,eAAO;AAAA;AAClB,eAAQ,OAAO,OAAM;AAAE,aAAK,OAAO,MAAM;AAAA;AAAA;AAE3C,WAAO;AAAA;AAAA,EAGT,UAAU,MAAM,IAAI,WAAW,UAAU,MAAM,OAAO,IAAG;AACvD,SAAK,cAAc,MAAM,KAAK,OAAO,CAAC,KAAK,MAAM,OAAO,SAAS;AAAA,MAC/D;AAAA,MACA,OAAO;AAAA,MACP,OAAO,KAAK,YAAY,IAAI,MAAM,KAAK;AAAA,MACvC,KAAK,KAAK,kBAAkB,IAAI,WAAW;AAAA;AAAA;AAAA,EAI/C,iBAAiB,QAAQ,UAAU,UAAU,UAAU,WAAW;AAAA,KAAI;AACpE,SAAK,WAAW,aAAa,OAAO,MAAM,CAAC,MAAM,cAAc;AAC7D,WAAK,cAAc,MAAM,YAAY;AAAA,QACnC,OAAO,OAAO,aAAa,KAAK,QAAQ;AAAA,QACxC,KAAK,OAAO,aAAa;AAAA,QACzB,WAAW;AAAA,QACX;AAAA,QACA,KAAK,KAAK,kBAAkB,OAAO,MAAM;AAAA,SACxC;AAAA;AAAA;AAAA,EAIP,UAAU,SAAS,WAAW,UAAU,UAAU,MAAM,UAAS;AAC/D,QAAI;AACJ,QAAI,MAAM,MAAM,YAAY,WAAW,KAAK,kBAAkB,QAAQ,MAAM;AAC5E,QAAI,eAAe,MAAM,KAAK,OAAO,CAAC,SAAS,QAAQ,OAAO,UAAU;AACxE,QAAI;AACJ,QAAG,QAAQ,aAAa,KAAK,QAAQ,YAAW;AAC9C,iBAAW,cAAc,QAAQ,MAAM,EAAC,SAAS,KAAK,WAAU,CAAC,QAAQ;AAAA,WACpE;AACL,iBAAW,cAAc,QAAQ,MAAM,EAAC,SAAS,KAAK;AAAA;AAExD,QAAG,YAAI,cAAc,YAAY,QAAQ,SAAS,QAAQ,MAAM,SAAS,GAAE;AACzE,mBAAa,WAAW,SAAS,MAAM,KAAK,QAAQ;AAAA;AAEtD,cAAU,aAAa,iBAAiB;AACxC,QAAI,QAAQ;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO;AAAA,MACP;AAAA,MACA;AAAA;AAEF,SAAK,cAAc,cAAc,SAAS,OAAO,UAAQ;AACvD,kBAAI,UAAU,SAAS,KAAK,WAAW,QAAQ;AAC/C,UAAG,YAAI,cAAc,YAAY,QAAQ,aAAa,4BAA4B,MAAK;AACrF,YAAG,aAAa,uBAAuB,SAAS,SAAS,GAAE;AACzD,cAAI,CAAC,KAAK,QAAQ;AAClB,eAAK,YAAY,QAAQ,MAAM,WAAW,KAAK,KAAK,CAAC,aAAa;AAChE,wBAAY,SAAS;AACrB,iBAAK,sBAAsB,QAAQ;AAAA;AAAA;AAAA,aAGlC;AACL,oBAAY,SAAS;AAAA;AAAA;AAAA;AAAA,EAK3B,sBAAsB,QAAO;AAC3B,QAAI,iBAAiB,KAAK,mBAAmB;AAC7C,QAAG,gBAAe;AAChB,UAAI,CAAC,KAAK,MAAM,OAAO,YAAY;AACnC,WAAK,aAAa;AAClB;AAAA;AAAA;AAAA,EAIJ,mBAAmB,QAAO;AACxB,WAAO,KAAK,YAAY,KAAK,CAAC,CAAC,IAAI,MAAM,OAAO,eAAe,GAAG,WAAW;AAAA;AAAA,EAG/E,eAAe,QAAQ,KAAK,MAAM,UAAS;AACzC,QAAG,KAAK,mBAAmB,SAAQ;AAAE,aAAO;AAAA;AAC5C,SAAK,YAAY,KAAK,CAAC,QAAQ,KAAK,MAAM;AAAA;AAAA,EAG5C,aAAa,QAAO;AAClB,SAAK,cAAc,KAAK,YAAY,OAAO,CAAC,CAAC,IAAI,KAAK,eAAe;AACnE,UAAG,GAAG,WAAW,SAAQ;AACvB,aAAK,SAAS;AACd,eAAO;AAAA,aACF;AACL,eAAO;AAAA;AAAA;AAAA;AAAA,EAKb,eAAe,QAAQ,WAAW,UAAU,MAAM,SAAQ;AACxD,QAAI,gBAAgB,QAAM;AACxB,UAAI,cAAc,kBAAkB,IAAI,GAAG,KAAK,QAAQ,sBAAsB,GAAG;AACjF,aAAO,CAAE,gBAAe,kBAAkB,IAAI,0BAA0B,GAAG;AAAA;AAE7E,QAAI,iBAAiB,QAAM;AACzB,aAAO,GAAG,aAAa,KAAK,QAAQ;AAAA;AAEtC,QAAI,eAAe,QAAM,GAAG,WAAW;AAEvC,QAAI,cAAc,QAAM,CAAC,SAAS,YAAY,UAAU,SAAS,GAAG;AAEpE,QAAI,eAAe,MAAM;AACvB,UAAI,eAAe,MAAM,KAAK,OAAO;AACrC,UAAI,WAAW,aAAa,OAAO;AACnC,UAAI,UAAU,aAAa,OAAO,cAAc,OAAO;AACvD,UAAI,SAAS,aAAa,OAAO,aAAa,OAAO;AAErD,cAAQ,QAAQ,YAAU;AACxB,eAAO,aAAa,cAAc,OAAO;AACzC,eAAO,WAAW;AAAA;AAEpB,aAAO,QAAQ,WAAS;AACtB,cAAM,aAAa,cAAc,MAAM;AACvC,cAAM,WAAW;AACjB,YAAG,MAAM,OAAM;AACb,gBAAM,aAAa,cAAc,MAAM;AACvC,gBAAM,WAAW;AAAA;AAAA;AAGrB,aAAO,aAAa,KAAK,QAAQ,mBAAmB;AACpD,aAAO,KAAK,OAAO,CAAC,QAAQ,OAAO,UAAU,OAAO,SAAS,OAAO,SAAS,UAAU;AAAA;AAGzF,QAAI,MAAM,KAAK,kBAAkB,QAAQ;AACzC,QAAG,aAAa,qBAAqB,SAAQ;AAC3C,UAAI,CAAC,KAAK,QAAQ;AAClB,UAAI,OAAO,MAAM,KAAK,eAAe,QAAQ,WAAW,UAAU,MAAM;AACxE,aAAO,KAAK,eAAe,QAAQ,KAAK,MAAM;AAAA,eACtC,aAAa,wBAAwB,QAAQ,SAAS,GAAE;AAChE,UAAI,CAAC,KAAK,OAAO;AACjB,UAAI,cAAc,MAAM,CAAC,KAAK,KAAK;AACnC,WAAK,YAAY,QAAQ,WAAW,KAAK,KAAK,CAAC,aAAa;AAC1D,YAAI,WAAW,cAAc,QAAQ;AACrC,aAAK,cAAc,aAAa,SAAS;AAAA,UACvC,MAAM;AAAA,UACN,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,WACC;AAAA;AAAA,WAEA;AACL,UAAI,WAAW,cAAc,QAAQ;AACrC,WAAK,cAAc,cAAc,SAAS;AAAA,QACxC,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,QACP;AAAA,SACC;AAAA;AAAA;AAAA,EAIP,YAAY,QAAQ,WAAW,KAAK,KAAK,YAAW;AAClD,QAAI,oBAAoB,KAAK;AAC7B,QAAI,WAAW,aAAa,iBAAiB;AAC7C,QAAI,0BAA0B,SAAS;AAGvC,aAAS,QAAQ,aAAW;AAC1B,UAAI,WAAW,IAAI,aAAa,SAAS,MAAM,MAAM;AACnD;AACA,YAAG,4BAA4B,GAAE;AAAE;AAAA;AAAA;AAGrC,WAAK,UAAU,WAAW;AAC1B,UAAI,UAAU,SAAS,UAAU,IAAI,WAAS,MAAM;AAEpD,UAAI,UAAU;AAAA,QACZ,KAAK,QAAQ,aAAa;AAAA,QAC1B;AAAA,QACA,KAAK,KAAK,kBAAkB,QAAQ,MAAM;AAAA;AAG5C,WAAK,IAAI,UAAU,MAAM,CAAC,6BAA6B;AAEvD,WAAK,cAAc,MAAM,gBAAgB,SAAS,UAAQ;AACxD,aAAK,IAAI,UAAU,MAAM,CAAC,0BAA0B;AACpD,YAAG,KAAK,OAAM;AACZ,eAAK,SAAS;AACd,cAAI,CAAC,WAAW,UAAU,KAAK;AAC/B,eAAK,IAAI,UAAU,MAAM,CAAC,mBAAmB,aAAa;AAAA,eACrD;AACL,cAAI,UAAU,CAAC,aAAa;AAC1B,iBAAK,QAAQ,QAAQ,MAAM;AACzB,kBAAG,KAAK,cAAc,mBAAkB;AAAE;AAAA;AAAA;AAAA;AAG9C,mBAAS,kBAAkB,MAAM,SAAS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvD,gBAAgB,MAAM,cAAa;AACjC,QAAI,SAAS,YAAI,iBAAiB,KAAK,IAAI,OAAO,QAAM,GAAG,SAAS;AACpE,QAAG,OAAO,WAAW,GAAE;AAAE,eAAS,gDAAgD;AAAA,eAC1E,OAAO,SAAS,GAAE;AAAE,eAAS,uDAAuD;AAAA,WACvF;AAAE,kBAAI,cAAc,OAAO,IAAI,mBAAmB,EAAC,QAAQ,EAAC,OAAO;AAAA;AAAA;AAAA,EAG1E,iBAAiB,MAAM,QAAQ,UAAS;AACtC,SAAK,WAAW,aAAa,MAAM,CAAC,MAAM,cAAc;AACtD,UAAI,QAAQ,KAAK,SAAS;AAC1B,UAAI,WAAW,KAAK,aAAa,KAAK,QAAQ,sBAAsB,KAAK,aAAa,KAAK,QAAQ;AAEnG,iBAAG,KAAK,UAAU,UAAU,MAAM,OAAO,CAAC,QAAQ,EAAC,SAAS,MAAM,MAAM,QAAgB;AAAA;AAAA;AAAA,EAI5F,cAAc,MAAM,UAAU,UAAS;AACrC,QAAI,UAAU,KAAK,WAAW,eAAe;AAC7C,QAAI,SAAS,WAAW,MAAM,KAAK,OAAO,CAAC,WAAW,WAAW;AACjE,QAAI,WAAW,MAAM,KAAK,WAAW,SAAS,OAAO,SAAS;AAE9D,QAAI,OAAO,KAAK,cAAc,QAAQ,cAAc,EAAC,KAAK,QAAO,UAAQ;AACvE,WAAK,WAAW,iBAAiB,MAAM;AACrC,YAAG,KAAK,eAAc;AACpB,eAAK,WAAW,YAAY,MAAM,MAAM,UAAU;AAAA,eAC7C;AACL,cAAG,KAAK,WAAW,kBAAkB,UAAS;AAC5C,iBAAK,OAAO;AAAA;AAEd,eAAK;AACL,sBAAY,SAAS;AAAA;AAAA;AAAA;AAK3B,QAAG,MAAK;AACN,WAAK,QAAQ,WAAW;AAAA,WACnB;AACL;AAAA;AAAA;AAAA,EAIJ,iBAAiB,MAAK;AACpB,QAAG,KAAK,cAAc,GAAE;AAAE,aAAO;AAAA;AAEjC,QAAI,YAAY,KAAK,QAAQ;AAC7B,QAAI,WAAW,SAAS,cAAc;AACtC,aAAS,YAAY;AAErB,WACE,YAAI,IAAI,KAAK,IAAI,QAAQ,cACtB,OAAO,UAAQ,KAAK,MAAM,KAAK,YAAY,OAC3C,OAAO,UAAQ,KAAK,SAAS,SAAS,GACtC,OAAO,UAAQ,KAAK,aAAa,KAAK,QAAQ,uBAAuB,UACrE,IAAI,UAAQ;AACX,UAAI,UAAU,SAAS,QAAQ,cAAc,YAAY,KAAK,QAAQ,cAAc,KAAK,aAAa;AACtG,UAAG,SAAQ;AACT,eAAO,CAAC,MAAM,SAAS,KAAK,kBAAkB;AAAA,aACzC;AACL,eAAO,CAAC,MAAM,MAAM;AAAA;AAAA,OAGvB,OAAO,CAAC,CAAC,MAAM,SAAS,YAAY;AAAA;AAAA,EAI3C,6BAA6B,eAAc;AACzC,QAAI,kBAAkB,cAAc,OAAO,SAAO;AAChD,aAAO,YAAI,sBAAsB,KAAK,IAAI,KAAK,WAAW;AAAA;AAE5D,QAAG,gBAAgB,SAAS,GAAE;AAC5B,WAAK,YAAY,KAAK,GAAG;AAEzB,WAAK,cAAc,MAAM,qBAAqB,EAAC,MAAM,mBAAkB,MAAM;AAG3E,aAAK,cAAc,KAAK,YAAY,OAAO,SAAO,gBAAgB,QAAQ,SAAS;AAInF,YAAI,wBAAwB,gBAAgB,OAAO,SAAO;AACxD,iBAAO,YAAI,sBAAsB,KAAK,IAAI,KAAK,WAAW;AAAA;AAG5D,YAAG,sBAAsB,SAAS,GAAE;AAClC,eAAK,cAAc,MAAM,kBAAkB,EAAC,MAAM,yBAAwB,CAAC,SAAS;AAClF,iBAAK,SAAS,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvC,YAAY,IAAG;AACb,WAAO,GAAG,aAAa,mBAAmB,KAAK,MAC7C,MAAM,GAAG,QAAQ,oBAAoB,UAAQ,KAAK,QAAQ,KAAK;AAAA;AAAA,EAGnE,WAAW,MAAM,WAAW,UAAU,OAAO,IAAG;AAC9C,gBAAI,WAAW,MAAM,mBAAmB;AACxC,QAAI,cAAc,KAAK,WAAW,QAAQ;AAC1C,QAAI,SAAS,MAAM,KAAK,KAAK;AAC7B,SAAK,WAAW,kBAAkB;AAClC,SAAK,eAAe,MAAM,WAAW,UAAU,MAAM,MAAM;AACzD,aAAO,QAAQ,WAAS,YAAI,UAAU,OAAO;AAC7C,WAAK,WAAW;AAAA;AAAA;AAAA,EAIpB,QAAQ,MAAK;AAAE,WAAO,KAAK,WAAW,QAAQ;AAAA;AAAA;;;ACz9BhD,uBAAgC;AAAA,EAC9B,YAAY,KAAK,WAAW,OAAO,IAAG;AACpC,SAAK,WAAW;AAChB,QAAG,CAAC,aAAa,UAAU,YAAY,SAAS,UAAS;AACvD,YAAM,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQlB,SAAK,SAAS,IAAI,UAAU,KAAK;AACjC,SAAK,gBAAgB,KAAK,iBAAiB;AAC3C,SAAK,OAAO;AACZ,SAAK,SAAS,QAAQ,KAAK,UAAU;AACrC,SAAK,aAAa,KAAK;AACvB,SAAK,oBAAoB,KAAK,YAAY;AAC1C,SAAK,WAAW,OAAO,OAAO,MAAM,WAAW,KAAK,YAAY;AAChE,SAAK,gBAAgB;AACrB,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,iBAAiB;AACtB,SAAK,uBAAuB;AAC5B,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,OAAO,OAAO,SAAS;AAC5B,SAAK,cAAc;AACnB,SAAK,kBAAkB,MAAM,OAAO;AACpC,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,gBAAgB,KAAK,iBAAiB;AAC3C,SAAK,wBAAwB;AAC7B,SAAK,aAAa,KAAK,cAAc;AACrC,SAAK,kBAAkB,KAAK,mBAAmB;AAC/C,SAAK,kBAAkB,KAAK,mBAAmB;AAC/C,SAAK,iBAAiB,KAAK,kBAAkB;AAC7C,SAAK,eAAe,KAAK,gBAAgB,OAAO;AAChD,SAAK,iBAAiB,KAAK,kBAAkB,OAAO;AACpD,SAAK,sBAAsB;AAC3B,SAAK,eAAe,OAAO,OAAO,EAAC,aAAa,WAAW,mBAAmB,aAAY,KAAK,OAAO;AACtG,SAAK,cAAc,IAAI;AACvB,WAAO,iBAAiB,YAAY,QAAM;AACxC,WAAK,WAAW;AAAA;AAElB,SAAK,OAAO,OAAO,MAAM;AACvB,UAAG,KAAK,cAAa;AAEnB,eAAO,SAAS;AAAA;AAAA;AAAA;AAAA,EAOtB,mBAAkB;AAAE,WAAO,KAAK,eAAe,QAAQ,oBAAoB;AAAA;AAAA,EAE3E,iBAAgB;AAAE,WAAO,KAAK,eAAe,QAAQ,kBAAkB;AAAA;AAAA,EAEvE,kBAAiB;AAAE,WAAO,KAAK,eAAe,QAAQ,kBAAkB;AAAA;AAAA,EAExE,cAAa;AAAE,SAAK,eAAe,QAAQ,cAAc;AAAA;AAAA,EAEzD,kBAAiB;AAAE,SAAK,eAAe,QAAQ,gBAAgB;AAAA;AAAA,EAE/D,eAAc;AAAE,SAAK,eAAe,QAAQ,cAAc;AAAA;AAAA,EAE1D,mBAAkB;AAAE,SAAK,eAAe,WAAW;AAAA;AAAA,EAEnD,iBAAiB,cAAa;AAC5B,SAAK;AACL,YAAQ,IAAI;AACZ,SAAK,eAAe,QAAQ,oBAAoB;AAAA;AAAA,EAGlD,oBAAmB;AAAE,SAAK,eAAe,WAAW;AAAA;AAAA,EAEpD,gBAAe;AACb,QAAI,MAAM,KAAK,eAAe,QAAQ;AACtC,WAAO,MAAM,SAAS,OAAO;AAAA;AAAA,EAG/B,YAAW;AAAE,WAAO,KAAK;AAAA;AAAA,EAEzB,UAAS;AAEP,QAAG,OAAO,SAAS,aAAa,eAAe,CAAC,KAAK,mBAAkB;AAAE,WAAK;AAAA;AAC9E,QAAI,YAAY,MAAM;AACpB,UAAG,KAAK,iBAAgB;AACtB,aAAK;AACL,aAAK,OAAO;AAAA,iBACJ,KAAK,MAAK;AAClB,aAAK,OAAO;AAAA;AAAA;AAGhB,QAAG,CAAC,YAAY,UAAU,eAAe,QAAQ,SAAS,eAAe,GAAE;AACzE;AAAA,WACK;AACL,eAAS,iBAAiB,oBAAoB,MAAM;AAAA;AAAA;AAAA,EAIxD,WAAW,UAAS;AAClB,iBAAa,KAAK;AAClB,SAAK,OAAO,WAAW;AAAA;AAAA,EAGzB,iBAAiB,WAAU;AACzB,iBAAa,KAAK;AAClB,SAAK,OAAO,iBAAiB;AAC7B,SAAK;AAAA;AAAA,EAGP,OAAO,IAAI,WAAW,YAAY,MAAK;AACrC,SAAK,MAAM,IAAI,UAAQ,WAAG,KAAK,WAAW,WAAW,MAAM;AAAA;AAAA,EAK7D,WAAW,MAAM,MAAK;AAAE,SAAK,aAAa,MAAM,GAAG;AAAA;AAAA,EAEnD,KAAK,MAAM,MAAK;AACd,QAAG,CAAC,KAAK,sBAAsB,CAAC,QAAQ,MAAK;AAAE,aAAO;AAAA;AACtD,YAAQ,KAAK;AACb,QAAI,SAAS;AACb,YAAQ,QAAQ;AAChB,WAAO;AAAA;AAAA,EAGT,IAAI,MAAM,MAAM,aAAY;AAC1B,QAAG,KAAK,YAAW;AACjB,UAAI,CAAC,KAAK,OAAO;AACjB,WAAK,WAAW,MAAM,MAAM,KAAK;AAAA,eACzB,KAAK,kBAAiB;AAC9B,UAAI,CAAC,KAAK,OAAO;AACjB,YAAM,MAAM,MAAM,KAAK;AAAA;AAAA;AAAA,EAI3B,iBAAiB,UAAS;AACxB,SAAK,YAAY,MAAM;AAAA;AAAA,EAGzB,WAAW,MAAM,SAAS,SAAS,WAAU;AAAA,KAAG;AAC9C,SAAK,YAAY,cAAc,MAAM,SAAS;AAAA;AAAA,EAGhD,UAAU,SAAS,OAAO,IAAG;AAC3B,YAAQ,GAAG,OAAO,UAAQ;AACxB,UAAI,UAAU,KAAK;AACnB,UAAG,CAAC,SAAQ;AACV,WAAG;AAAA,aACE;AACL,gBAAQ,IAAI,cAAc;AAC1B,mBAAW,MAAM,GAAG,OAAO;AAAA;AAAA;AAAA;AAAA,EAKjC,SAAS,MAAM,MAAM,MAAK;AACxB,QAAI,UAAU,KAAK;AACnB,QAAI,eAAe,KAAK;AACxB,QAAG,CAAC,SAAQ;AACV,UAAG,KAAK,iBAAiB,KAAK,SAAQ;AACpC,eAAO,OAAO,QAAQ,WAAW,MAAM;AACrC,cAAG,KAAK,cAAc,gBAAgB,CAAC,KAAK,eAAc;AACxD,iBAAK,iBAAiB,MAAM,MAAM;AAChC,mBAAK,IAAI,MAAM,WAAW,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA,aAIlC;AACL,eAAO;AAAA;AAAA;AAIX,YAAQ,IAAI,cAAc;AAC1B,QAAI,WAAW;AAAA,MACb,UAAU;AAAA,MACV,QAAQ,MAAM,IAAG;AAAE,aAAK,SAAS,KAAK,CAAC,MAAM;AAAA;AAAA;AAE/C,eAAW,MAAM;AACf,UAAG,KAAK,eAAc;AAAE;AAAA;AACxB,eAAS,SAAS,OAAO,CAAC,KAAK,CAAC,MAAM,QAAQ,IAAI,QAAQ,MAAM,KAAK;AAAA,OACpE;AACH,WAAO;AAAA;AAAA,EAGT,iBAAiB,MAAM,KAAI;AACzB,iBAAa,KAAK;AAClB,SAAK;AACL,QAAI,QAAQ,KAAK;AACjB,QAAI,QAAQ,KAAK;AACjB,QAAI,UAAU,KAAK,MAAM,KAAK,WAAY,SAAQ,QAAQ,MAAM;AAChE,QAAI,QAAQ,gBAAQ,YAAY,KAAK,cAAc,OAAO,SAAS,UAAU,qBAAqB,GAAG,WAAS,QAAQ;AACtH,QAAG,QAAQ,KAAK,YAAW;AACzB,gBAAU,KAAK;AAAA;AAEjB,SAAK,wBAAwB,WAAW,MAAM;AAE5C,UAAG,KAAK,iBAAiB,KAAK,eAAc;AAAE;AAAA;AAC9C,WAAK;AACL,YAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,MAAM,CAAC,eAAe;AAC3D,UAAG,QAAQ,KAAK,YAAW;AACzB,aAAK,IAAI,MAAM,QAAQ,MAAM,CAAC,YAAY,KAAK;AAAA;AAEjD,UAAG,KAAK,kBAAiB;AACvB,eAAO,WAAW,KAAK;AAAA,aAClB;AACL,eAAO,SAAS;AAAA;AAAA,OAEjB;AAAA;AAAA,EAGL,iBAAiB,MAAK;AACpB,WAAO,QAAQ,KAAK,WAAW,cAAc,cAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA;AAAA,EAGtF,aAAY;AAAE,WAAO,KAAK;AAAA;AAAA,EAE1B,cAAa;AAAE,WAAO,KAAK,OAAO;AAAA;AAAA,EAElC,mBAAkB;AAAE,WAAO,KAAK;AAAA;AAAA,EAEhC,QAAQ,MAAK;AAAE,WAAO,GAAG,KAAK,qBAAqB;AAAA;AAAA,EAEnD,QAAQ,OAAO,QAAO;AAAE,WAAO,KAAK,OAAO,QAAQ,OAAO;AAAA;AAAA,EAE1D,gBAAe;AACb,QAAI,aAAa;AACjB,gBAAI,IAAI,UAAU,GAAG,0BAA0B,mBAAmB,YAAU;AAC1E,UAAG,CAAC,KAAK,YAAY,OAAO,KAAI;AAC9B,YAAI,OAAO,KAAK,YAAY;AAC5B,aAAK,QAAQ,KAAK;AAClB,aAAK;AACL,YAAG,OAAO,aAAa,WAAU;AAAE,eAAK,OAAO;AAAA;AAAA;AAEjD,mBAAa;AAAA;AAEf,WAAO;AAAA;AAAA,EAGT,SAAS,IAAI,OAAM;AACjB,SAAK;AACL,oBAAQ,SAAS,IAAI;AAAA;AAAA,EAGvB,YAAY,MAAM,OAAO,WAAW,MAAM,UAAU,KAAK,eAAe,OAAM;AAC5E,SAAK,iBAAiB,KAAK,kBAAkB,KAAK,KAAK;AACvD,QAAI,YAAY,YAAI,UAAU,KAAK,gBAAgB;AACnD,SAAK,KAAK,WAAW,KAAK;AAC1B,SAAK,KAAK;AAEV,SAAK,OAAO,KAAK,YAAY,WAAW;AACxC,SAAK,KAAK,YAAY;AACtB,SAAK;AACL,SAAK,KAAK,KAAK,CAAC,WAAW,WAAW;AACpC,UAAG,cAAc,KAAK,KAAK,kBAAkB,UAAS;AACpD,aAAK,iBAAiB,MAAM;AAC1B,sBAAI,cAAc,UAAU,QAAQ,QAAM,UAAU,YAAY;AAChE,eAAK,eAAe,YAAY;AAChC,eAAK,iBAAiB;AACtB,sBAAY,sBAAsB;AAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,kBAAkB,UAAS;AACzB,QAAI,aAAa,KAAK,QAAQ;AAC9B,eAAW,YAAY,YAAI,IAAI,UAAU,IAAI;AAC7C,aAAS,QAAQ,QAAM;AACrB,UAAG,SAAS,KAAK,SAAS,KAAI;AAC5B,aAAK,OAAO,IAAI,GAAG,aAAa,aAAa;AAAA;AAAA;AAAA;AAAA,EAKnD,UAAU,IAAG;AAAE,WAAO,GAAG,gBAAgB,GAAG,aAAa,iBAAiB;AAAA;AAAA,EAE1E,YAAY,IAAI,OAAM;AACpB,QAAI,OAAO,IAAI,KAAK,IAAI,MAAM,MAAM;AACpC,SAAK,MAAM,KAAK,MAAM;AACtB,WAAO;AAAA;AAAA,EAGT,MAAM,SAAS,UAAS;AACtB,QAAI,OAAO,MAAM,QAAQ,QAAQ,oBAAoB,QAAM,KAAK,YAAY,QAAQ,KAAK;AACzF,QAAG,MAAK;AAAE,eAAS;AAAA;AAAA;AAAA,EAGrB,aAAa,SAAS,UAAS;AAC7B,SAAK,MAAM,SAAS,UAAQ,SAAS,MAAM;AAAA;AAAA,EAG7C,YAAY,IAAG;AACb,QAAI,SAAS,GAAG,aAAa;AAC7B,WAAO,MAAM,KAAK,YAAY,SAAS,UAAQ,KAAK,kBAAkB;AAAA;AAAA,EAGxE,YAAY,IAAG;AAAE,WAAO,KAAK,MAAM;AAAA;AAAA,EAEnC,kBAAiB;AACf,aAAQ,MAAM,KAAK,OAAM;AACvB,WAAK,MAAM,IAAI;AACf,aAAO,KAAK,MAAM;AAAA;AAEpB,SAAK,OAAO;AAAA;AAAA,EAGd,gBAAgB,IAAG;AACjB,QAAI,OAAO,KAAK,YAAY,GAAG,aAAa;AAC5C,QAAG,QAAQ,KAAK,OAAO,GAAG,IAAG;AAC3B,WAAK;AACL,aAAO,KAAK,MAAM,KAAK;AAAA,eACf,MAAK;AACb,WAAK,kBAAkB,GAAG;AAAA;AAAA;AAAA,EAI9B,iBAAiB,QAAO;AACtB,QAAG,KAAK,kBAAkB,QAAO;AAAE;AAAA;AACnC,SAAK,gBAAgB;AACrB,QAAI,SAAS,MAAM;AACjB,UAAG,WAAW,KAAK,eAAc;AAAE,aAAK,gBAAgB;AAAA;AACxD,aAAO,oBAAoB,WAAW;AACtC,aAAO,oBAAoB,YAAY;AAAA;AAEzC,WAAO,iBAAiB,WAAW;AACnC,WAAO,iBAAiB,YAAY;AAAA;AAAA,EAGtC,mBAAkB;AAChB,QAAG,SAAS,kBAAkB,SAAS,MAAK;AAC1C,aAAO,KAAK,iBAAiB,SAAS;AAAA,WACjC;AAEL,aAAO,SAAS,iBAAiB,SAAS;AAAA;AAAA;AAAA,EAI9C,kBAAkB,MAAK;AACrB,QAAG,KAAK,cAAc,KAAK,YAAY,KAAK,aAAY;AACtD,WAAK,aAAa;AAAA;AAAA;AAAA,EAItB,+BAA8B;AAC5B,QAAG,KAAK,cAAc,KAAK,eAAe,SAAS,MAAK;AACtD,WAAK,WAAW;AAAA;AAAA;AAAA,EAIpB,oBAAmB;AACjB,SAAK,aAAa,KAAK;AACvB,QAAG,KAAK,eAAe,SAAS,MAAK;AAAE,WAAK,WAAW;AAAA;AAAA;AAAA,EAGzD,qBAAoB;AAClB,QAAG,KAAK,qBAAoB;AAAE;AAAA;AAE9B,SAAK,sBAAsB;AAE3B,SAAK,OAAO,QAAQ,WAAS;AAC3B,UAAG,SAAS,MAAM,SAAS,OAAQ,KAAK,MAAK;AAC3C,aAAK,iBAAiB,KAAK;AAAA;AAAA;AAG/B,aAAS,KAAK,iBAAiB,SAAS,WAAW;AAAA;AACnD,WAAO,iBAAiB,YAAY,OAAK;AACvC,UAAG,EAAE,WAAU;AACb,aAAK,YAAY;AACjB,aAAK,gBAAgB,EAAC,IAAI,OAAO,SAAS,MAAM,MAAM;AACtD,eAAO,SAAS;AAAA;AAAA,OAEjB;AACH,SAAK;AACL,SAAK;AACL,SAAK;AACL,SAAK,KAAK,EAAC,OAAO,SAAS,SAAS,aAAY,CAAC,GAAG,MAAM,MAAM,UAAU,UAAU,gBAAgB;AAClG,UAAI,WAAW,SAAS,aAAa,KAAK,QAAQ;AAClD,UAAI,aAAa,EAAE,OAAO,EAAE,IAAI;AAChC,UAAG,YAAY,SAAS,kBAAkB,YAAW;AAAE;AAAA;AAEvD,UAAI,OAAO,EAAC,KAAK,EAAE,QAAQ,KAAK,UAAU,MAAM,GAAG;AACnD,iBAAG,KAAK,MAAM,UAAU,MAAM,UAAU,CAAC,QAAQ,EAAC;AAAA;AAEpD,SAAK,KAAK,EAAC,MAAM,YAAY,OAAO,aAAY,CAAC,GAAG,MAAM,MAAM,UAAU,UAAU,gBAAgB;AAClG,UAAG,CAAC,aAAY;AACd,YAAI,OAAO,EAAC,KAAK,EAAE,QAAQ,KAAK,UAAU,MAAM,GAAG;AACnD,mBAAG,KAAK,MAAM,UAAU,MAAM,UAAU,CAAC,QAAQ,EAAC;AAAA;AAAA;AAGtD,SAAK,KAAK,EAAC,MAAM,QAAQ,OAAO,WAAU,CAAC,GAAG,MAAM,MAAM,UAAU,WAAW,UAAU,cAAc;AAErG,UAAG,cAAc,UAAS;AACxB,YAAI,OAAO,KAAK,UAAU,MAAM,GAAG;AACnC,mBAAG,KAAK,MAAM,UAAU,MAAM,UAAU,CAAC,QAAQ,EAAC;AAAA;AAAA;AAGtD,WAAO,iBAAiB,YAAY,OAAK,EAAE;AAC3C,WAAO,iBAAiB,QAAQ,OAAK;AACnC,QAAE;AACF,UAAI,eAAe,MAAM,kBAAkB,EAAE,QAAQ,KAAK,QAAQ,mBAAmB,gBAAc;AACjG,eAAO,WAAW,aAAa,KAAK,QAAQ;AAAA;AAE9C,UAAI,aAAa,gBAAgB,SAAS,eAAe;AACzD,UAAI,QAAQ,MAAM,KAAK,EAAE,aAAa,SAAS;AAC/C,UAAG,CAAC,cAAc,WAAW,YAAY,MAAM,WAAW,KAAK,CAAE,YAAW,iBAAiB,WAAU;AAAE;AAAA;AAEzG,mBAAa,WAAW,YAAY;AACpC,iBAAW,cAAc,IAAI,MAAM,SAAS,EAAC,SAAS;AAAA;AAExD,SAAK,GAAG,mBAAmB,OAAK;AAC9B,UAAI,eAAe,EAAE;AACrB,UAAG,CAAC,YAAI,cAAc,eAAc;AAAE;AAAA;AACtC,UAAI,QAAQ,MAAM,KAAK,EAAE,OAAO,SAAS,IAAI,OAAO,OAAK,aAAa,QAAQ,aAAa;AAC3F,mBAAa,WAAW,cAAc;AACtC,mBAAa,cAAc,IAAI,MAAM,SAAS,EAAC,SAAS;AAAA;AAAA;AAAA,EAI5D,UAAU,WAAW,GAAG,UAAS;AAC/B,QAAI,WAAW,KAAK,kBAAkB;AACtC,WAAO,WAAW,SAAS,GAAG,YAAY;AAAA;AAAA,EAG5C,eAAe,MAAK;AAClB,SAAK;AACL,SAAK,cAAc;AACnB,WAAO,KAAK;AAAA;AAAA,EAGd,kBAAkB,SAAQ;AACxB,QAAG,KAAK,YAAY,SAAQ;AAC1B,aAAO;AAAA,WACF;AACL,WAAK,OAAO,KAAK;AACjB,WAAK,cAAc;AACnB,aAAO;AAAA;AAAA;AAAA,EAIX,UAAS;AAAE,WAAO,KAAK;AAAA;AAAA,EAEvB,iBAAgB;AAAE,WAAO,CAAC,CAAC,KAAK;AAAA;AAAA,EAEhC,KAAK,QAAQ,UAAS;AACpB,aAAQ,SAAS,QAAO;AACtB,UAAI,mBAAmB,OAAO;AAE9B,WAAK,GAAG,kBAAkB,OAAK;AAC7B,YAAI,UAAU,KAAK,QAAQ;AAC3B,YAAI,gBAAgB,KAAK,QAAQ,UAAU;AAC3C,YAAI,iBAAiB,EAAE,OAAO,gBAAgB,EAAE,OAAO,aAAa;AACpE,YAAG,gBAAe;AAChB,eAAK,SAAS,EAAE,QAAQ,GAAG,kBAAkB,MAAM;AACjD,iBAAK,aAAa,EAAE,QAAQ,UAAQ;AAClC,uBAAS,GAAG,OAAO,MAAM,EAAE,QAAQ,gBAAgB;AAAA;AAAA;AAAA,eAGlD;AACL,sBAAI,IAAI,UAAU,IAAI,kBAAkB,QAAM;AAC5C,gBAAI,WAAW,GAAG,aAAa;AAC/B,iBAAK,SAAS,IAAI,GAAG,kBAAkB,MAAM;AAC3C,mBAAK,aAAa,IAAI,UAAQ;AAC5B,yBAAS,GAAG,OAAO,MAAM,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrD,aAAY;AACV,WAAO,iBAAiB,aAAa,OAAK,KAAK,uBAAuB,EAAE;AACxE,SAAK,UAAU,SAAS,SAAS;AACjC,SAAK,UAAU,aAAa,iBAAiB;AAAA;AAAA,EAG/C,UAAU,WAAW,aAAa,SAAQ;AACxC,QAAI,QAAQ,KAAK,QAAQ;AACzB,WAAO,iBAAiB,WAAW,OAAK;AACtC,UAAI,SAAS;AACb,UAAG,SAAQ;AACT,iBAAS,EAAE,OAAO,QAAQ,IAAI,YAAY,EAAE,SAAS,EAAE,OAAO,cAAc,IAAI;AAAA,aAC3E;AACL,YAAI,uBAAuB,KAAK,wBAAwB,EAAE;AAC1D,iBAAS,kBAAkB,sBAAsB;AACjD,aAAK,kBAAkB,GAAG;AAC1B,aAAK,uBAAuB;AAAA;AAE9B,UAAI,WAAW,UAAU,OAAO,aAAa;AAC7C,UAAG,CAAC,UAAS;AAAE;AAAA;AACf,UAAG,OAAO,aAAa,YAAY,KAAI;AAAE,UAAE;AAAA;AAE3C,WAAK,SAAS,QAAQ,GAAG,SAAS,MAAM;AACtC,aAAK,aAAa,QAAQ,UAAQ;AAChC,qBAAG,KAAK,SAAS,UAAU,MAAM,QAAQ,CAAC,QAAQ,EAAC,MAAM,KAAK,UAAU,SAAS,GAAG;AAAA;AAAA;AAAA,OAGvF;AAAA;AAAA,EAGL,kBAAkB,GAAG,gBAAe;AAClC,QAAI,eAAe,KAAK,QAAQ;AAChC,gBAAI,IAAI,UAAU,IAAI,iBAAiB,QAAM;AAC3C,UAAG,CAAE,IAAG,WAAW,mBAAmB,GAAG,SAAS,kBAAiB;AACjE,aAAK,aAAa,EAAE,QAAQ,UAAQ;AAClC,cAAI,WAAW,GAAG,aAAa;AAC/B,cAAG,WAAG,UAAU,KAAI;AAClB,uBAAG,KAAK,SAAS,UAAU,MAAM,IAAI,CAAC,QAAQ,EAAC,MAAM,KAAK,UAAU,SAAS,GAAG,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO5F,UAAS;AACP,QAAG,CAAC,gBAAQ,gBAAe;AAAE;AAAA;AAC7B,QAAG,QAAQ,mBAAkB;AAAE,cAAQ,oBAAoB;AAAA;AAC3D,QAAI,cAAc;AAClB,WAAO,iBAAiB,UAAU,QAAM;AACtC,mBAAa;AACb,oBAAc,WAAW,MAAM;AAC7B,wBAAQ,mBAAmB,WAAS,OAAO,OAAO,OAAO,EAAC,QAAQ,OAAO;AAAA,SACxE;AAAA;AAEL,WAAO,iBAAiB,YAAY,WAAS;AAC3C,UAAG,CAAC,KAAK,oBAAoB,OAAO,WAAU;AAAE;AAAA;AAChD,UAAI,EAAC,MAAM,IAAI,MAAM,WAAU,MAAM,SAAS;AAC9C,UAAI,OAAO,OAAO,SAAS;AAE3B,WAAK,iBAAiB,MAAM;AAC1B,YAAG,KAAK,KAAK,iBAAkB,UAAS,WAAW,OAAO,KAAK,KAAK,KAAI;AACtE,eAAK,KAAK,cAAc,MAAM;AAAA,eACzB;AACL,eAAK,YAAY,MAAM,MAAM,MAAM;AACjC,gBAAG,MAAK;AAAE,mBAAK;AAAA;AACf,gBAAG,OAAO,WAAY,UAAS;AAC7B,yBAAW,MAAM;AACf,uBAAO,SAAS,GAAG;AAAA,iBAClB;AAAA;AAAA;AAAA;AAAA;AAAA,OAKV;AACH,WAAO,iBAAiB,SAAS,OAAK;AACpC,UAAI,SAAS,kBAAkB,EAAE,QAAQ;AACzC,UAAI,OAAO,UAAU,OAAO,aAAa;AACzC,UAAI,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW;AACzD,UAAG,CAAC,QAAQ,CAAC,KAAK,iBAAiB,CAAC,KAAK,QAAQ,aAAY;AAAE;AAAA;AAE/D,UAAI,OAAO,OAAO;AAClB,UAAI,YAAY,OAAO,aAAa;AACpC,QAAE;AACF,QAAE;AACF,UAAG,KAAK,gBAAgB,MAAK;AAAE;AAAA;AAE/B,WAAK,iBAAiB,MAAM;AAC1B,YAAG,SAAS,SAAQ;AAClB,eAAK,iBAAiB,MAAM,WAAW;AAAA,mBAC/B,SAAS,YAAW;AAC5B,eAAK,gBAAgB,MAAM;AAAA,eACtB;AACL,gBAAM,IAAI,MAAM,YAAY,mDAAmD;AAAA;AAAA;AAAA,OAGlF;AAAA;AAAA,EAGL,cAAc,OAAO,UAAU,IAAG;AAChC,gBAAI,cAAc,QAAQ,OAAO,SAAS,EAAC,QAAQ;AAAA;AAAA,EAGrD,eAAe,QAAO;AACpB,WAAO,QAAQ,CAAC,CAAC,OAAO,aAAa,KAAK,cAAc,OAAO;AAAA;AAAA,EAGjE,gBAAgB,MAAM,UAAS;AAC7B,gBAAI,cAAc,QAAQ,0BAA0B,EAAC,QAAQ;AAC7D,QAAI,OAAO,MAAM,YAAI,cAAc,QAAQ,yBAAyB,EAAC,QAAQ;AAC7E,WAAO,WAAW,SAAS,QAAQ;AAAA;AAAA,EAGrC,iBAAiB,MAAM,WAAW,UAAS;AACzC,SAAK,gBAAgB,EAAC,IAAI,MAAM,MAAM,WAAU,UAAQ;AACtD,WAAK,KAAK,cAAc,MAAM,UAAU,aAAW;AACjD,aAAK,aAAa,MAAM,WAAW;AACnC;AAAA;AAAA;AAAA;AAAA,EAKN,aAAa,MAAM,WAAW,UAAU,KAAK,eAAe,OAAM;AAChE,QAAG,CAAC,KAAK,kBAAkB,UAAS;AAAE;AAAA;AAEtC,oBAAQ,UAAU,WAAW,EAAC,MAAM,SAAS,IAAI,KAAK,KAAK,MAAK;AAChE,SAAK,oBAAoB,OAAO;AAAA;AAAA,EAGlC,gBAAgB,MAAM,WAAW,OAAM;AACrC,QAAI,SAAS,OAAO;AACpB,SAAK,gBAAgB,EAAC,IAAI,MAAM,MAAM,cAAa,UAAQ;AACzD,WAAK,YAAY,MAAM,OAAO,MAAM;AAClC,wBAAQ,UAAU,WAAW,EAAC,MAAM,YAAY,IAAI,KAAK,KAAK,IAAI,UAAiB;AACnF,aAAK,oBAAoB,OAAO;AAChC;AAAA;AAAA;AAAA;AAAA,EAKN,qBAAoB;AAClB,oBAAQ,UAAU,WAAW,EAAC,MAAM,MAAM,MAAM,SAAS,IAAI,KAAK,KAAK;AAAA;AAAA,EAGzE,oBAAoB,aAAY;AAC9B,QAAI,EAAC,UAAU,WAAU,KAAK;AAC9B,QAAG,WAAW,WAAW,YAAY,WAAW,YAAY,QAAO;AACjE,aAAO;AAAA,WACF;AACL,WAAK,kBAAkB,MAAM;AAC7B,aAAO;AAAA;AAAA;AAAA,EAIX,YAAW;AACT,QAAI,aAAa;AACjB,SAAK,GAAG,UAAU,OAAK;AACrB,UAAI,WAAW,EAAE,OAAO,aAAa,KAAK,QAAQ;AAClD,UAAG,CAAC,UAAS;AAAE;AAAA;AACf,QAAE;AACF,QAAE,OAAO,WAAW;AACpB,WAAK,aAAa,EAAE,QAAQ,UAAQ;AAClC,mBAAG,KAAK,UAAU,UAAU,MAAM,EAAE,QAAQ,CAAC,QAAQ;AAAA;AAAA,OAEtD;AAEH,aAAQ,QAAQ,CAAC,UAAU,UAAS;AAClC,WAAK,GAAG,MAAM,OAAK;AACjB,YAAI,YAAY,KAAK,QAAQ;AAC7B,YAAI,QAAQ,EAAE;AACd,YAAI,aAAa,MAAM,aAAa;AACpC,YAAI,YAAY,MAAM,QAAQ,MAAM,KAAK,aAAa;AACtD,YAAI,WAAW,cAAc;AAC7B,YAAG,CAAC,UAAS;AAAE;AAAA;AACf,YAAG,MAAM,SAAS,YAAY,MAAM,YAAY,MAAM,SAAS,UAAS;AAAE;AAAA;AAE1E,YAAI,aAAa,aAAa,QAAQ,MAAM;AAC5C,YAAI,oBAAoB;AACxB;AACA,YAAI,EAAC,IAAQ,MAAM,aAAY,YAAI,QAAQ,OAAO,qBAAqB;AAEvE,YAAG,OAAO,oBAAoB,KAAK,SAAS,UAAS;AAAE;AAAA;AAEvD,oBAAI,WAAW,OAAO,kBAAkB,EAAC,IAAI,mBAAmB;AAEhE,aAAK,SAAS,OAAO,GAAG,MAAM,MAAM;AAClC,eAAK,aAAa,YAAY,UAAQ;AACpC,wBAAI,WAAW,OAAO,iBAAiB;AACvC,gBAAG,CAAC,YAAI,eAAe,QAAO;AAC5B,mBAAK,iBAAiB;AAAA;AAExB,uBAAG,KAAK,UAAU,UAAU,MAAM,OAAO,CAAC,QAAQ,EAAC,SAAS,EAAE,OAAO,MAAM;AAAA;AAAA;AAAA,SAG9E;AAAA;AAAA;AAAA,EAIP,SAAS,IAAI,OAAO,WAAW,UAAS;AACtC,QAAG,cAAc,UAAU,cAAc,YAAW;AAAE,aAAO;AAAA;AAE7D,QAAI,cAAc,KAAK,QAAQ;AAC/B,QAAI,cAAc,KAAK,QAAQ;AAC/B,QAAI,kBAAkB,KAAK,SAAS,SAAS;AAC7C,QAAI,kBAAkB,KAAK,SAAS,SAAS;AAE7C,SAAK,aAAa,IAAI,UAAQ;AAC5B,UAAI,cAAc,MAAM,CAAC,KAAK,iBAAiB,SAAS,KAAK,SAAS;AACtE,kBAAI,SAAS,IAAI,OAAO,aAAa,iBAAiB,aAAa,iBAAiB,aAAa,MAAM;AACrG;AAAA;AAAA;AAAA;AAAA,EAKN,cAAc,UAAS;AACrB,SAAK,WAAW;AAChB;AACA,SAAK,WAAW;AAAA;AAAA,EAGlB,GAAG,OAAO,UAAS;AACjB,WAAO,iBAAiB,OAAO,OAAK;AAClC,UAAG,CAAC,KAAK,UAAS;AAAE,iBAAS;AAAA;AAAA;AAAA;AAAA;AAKnC,0BAAoB;AAAA,EAClB,cAAa;AACX,SAAK,cAAc,IAAI;AACvB,SAAK,aAAa;AAClB,SAAK;AAAA;AAAA,EAGP,QAAO;AACL,SAAK,YAAY,QAAQ,WAAS;AAChC,oBAAc;AACd,WAAK,YAAY,OAAO;AAAA;AAE1B,SAAK;AAAA;AAAA,EAGP,MAAM,UAAS;AACb,QAAG,KAAK,WAAW,GAAE;AACnB;AAAA,WACK;AACL,WAAK,cAAc;AAAA;AAAA;AAAA,EAIvB,cAAc,MAAM,SAAS,QAAO;AAClC;AACA,QAAI,QAAQ,WAAW,MAAM;AAC3B,WAAK,YAAY,OAAO;AACxB;AACA,UAAG,KAAK,WAAW,GAAE;AAAE,aAAK;AAAA;AAAA,OAC3B;AACH,SAAK,YAAY,IAAI;AAAA;AAAA,EAGvB,cAAc,IAAG;AAAE,SAAK,WAAW,KAAK;AAAA;AAAA,EAExC,OAAM;AAAE,WAAO,KAAK,YAAY;AAAA;AAAA,EAEhC,kBAAiB;AACf,SAAK,WAAW,QAAQ,QAAM;AAC9B,SAAK,aAAa;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|