tangled
alpha
login
or
join now
evan.jarrett.net
/
at-container-registry
66
fork
atom
A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
atcr.io
docker
container
atproto
go
66
fork
atom
overview
issues
1
pulls
pipelines
admin panel fixes
evan.jarrett.net
3 weeks ago
22b2d69c
5615dd41
verified
This commit was signed with the committer's
known signature
.
evan.jarrett.net
SSH Key Fingerprint:
SHA256:bznk0uVPp7XFOl67P0uTM1pCjf2A4ojeP/lsUE7uauQ=
2/2
lint.yaml
success
3min 45s
tests.yml
success
3min 35s
+431
-116
9 changed files
expand all
collapse all
unified
split
pkg
appview
public
js
bundle.min.js
src
js
app.js
hold
admin
admin.go
handlers_gc.go
templates
partials
gc_preview.html
gc_progress.html
relay_status.html
tab_storage.html
gc
gc.go
+2
-2
pkg/appview/public/js/bundle.min.js
···
1
1
-
var se=(function(){"use strict";let htmx={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){return getInputValues(e,t||"post").values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:!0,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null,disableInheritance:!1,responseHandling:[{code:"204",swap:!1},{code:"[23]..",swap:!0},{code:"[45]..",swap:!1,error:!0}],allowNestedOobSwaps:!0,historyRestoreAsHxRequest:!0,reportValidityOfForms:!1},parseInterval:null,location,_:null,version:"2.0.8"};htmx.onLoad=onLoadHelper,htmx.process=processNode,htmx.on=addEventListenerImpl,htmx.off=removeEventListenerImpl,htmx.trigger=triggerEvent,htmx.ajax=ajaxHelper,htmx.find=find,htmx.findAll=findAll,htmx.closest=closest,htmx.remove=removeElement,htmx.addClass=addClassToElement,htmx.removeClass=removeClassFromElement,htmx.toggleClass=toggleClassOnElement,htmx.takeClass=takeClassForElement,htmx.swap=swap,htmx.defineExtension=defineExtension,htmx.removeExtension=removeExtension,htmx.logAll=logAll,htmx.logNone=logNone,htmx.parseInterval=parseInterval,htmx._=internalEval;let internalAPI={addTriggerHandler,bodyContains,canAccessLocalStorage,findThisElement,filterValues,swap,hasAttribute,getAttributeValue,getClosestAttributeValue,getClosestMatch,getExpressionVars,getHeaders,getInputValues,getInternalData,getSwapSpecification,getTriggerSpecs,getTarget,makeFragment,mergeObjects,makeSettleInfo,oobSwap,querySelectorExt,settleImmediately,shouldCancel,triggerEvent,triggerErrorEvent,withExtensions},VERBS=["get","post","put","delete","patch"],VERB_SELECTOR=VERBS.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function parseInterval(e){if(e==null)return;let t=NaN;return e.slice(-2)=="ms"?t=parseFloat(e.slice(0,-2)):e.slice(-1)=="s"?t=parseFloat(e.slice(0,-1))*1e3:e.slice(-1)=="m"?t=parseFloat(e.slice(0,-1))*1e3*60:t=parseFloat(e),isNaN(t)?void 0:t}function getRawAttribute(e,t){return e instanceof Element&&e.getAttribute(t)}function hasAttribute(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function getAttributeValue(e,t){return getRawAttribute(e,t)||getRawAttribute(e,"data-"+t)}function parentElt(e){let t=e.parentElement;return!t&&e.parentNode instanceof ShadowRoot?e.parentNode:t}function getDocument(){return document}function getRootNode(e,t){return e.getRootNode?e.getRootNode({composed:t}):getDocument()}function getClosestMatch(e,t){for(;e&&!t(e);)e=parentElt(e);return e||null}function getAttributeValueWithDisinheritance(e,t,n){let r=getAttributeValue(t,n),o=getAttributeValue(t,"hx-disinherit");var i=getAttributeValue(t,"hx-inherit");if(e!==t){if(htmx.config.disableInheritance)return i&&(i==="*"||i.split(" ").indexOf(n)>=0)?r:null;if(o&&(o==="*"||o.split(" ").indexOf(n)>=0))return"unset"}return r}function getClosestAttributeValue(e,t){let n=null;if(getClosestMatch(e,function(r){return!!(n=getAttributeValueWithDisinheritance(e,asElement(r),t))}),n!=="unset")return n}function matches(e,t){return e instanceof Element&&e.matches(t)}function getStartTag(e){let n=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i.exec(e);return n?n[1].toLowerCase():""}function parseHTML(e){return"parseHTMLUnsafe"in Document?Document.parseHTMLUnsafe(e):new DOMParser().parseFromString(e,"text/html")}function takeChildrenFor(e,t){for(;t.childNodes.length>0;)e.append(t.childNodes[0])}function duplicateScript(e){let t=getDocument().createElement("script");return forEach(e.attributes,function(n){t.setAttribute(n.name,n.value)}),t.textContent=e.textContent,t.async=!1,htmx.config.inlineScriptNonce&&(t.nonce=htmx.config.inlineScriptNonce),t}function isJavaScriptScriptNode(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function normalizeScriptTags(e){Array.from(e.querySelectorAll("script")).forEach(t=>{if(isJavaScriptScriptNode(t)){let n=duplicateScript(t),r=t.parentNode;try{r.insertBefore(n,t)}catch(o){logError(o)}finally{t.remove()}}})}function makeFragment(e){let t=e.replace(/<head(\s[^>]*)?>[\s\S]*?<\/head>/i,""),n=getStartTag(t),r;if(n==="html"){r=new DocumentFragment;let i=parseHTML(e);takeChildrenFor(r,i.body),r.title=i.title}else if(n==="body"){r=new DocumentFragment;let i=parseHTML(t);takeChildrenFor(r,i.body),r.title=i.title}else{let i=parseHTML('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content,r.title=i.title;var o=r.querySelector("title");o&&o.parentNode===r&&(o.remove(),r.title=o.innerText)}return r&&(htmx.config.allowScriptTags?normalizeScriptTags(r):r.querySelectorAll("script").forEach(i=>i.remove())),r}function maybeCall(e){e&&e()}function isType(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function isFunction(e){return typeof e=="function"}function isRawObject(e){return isType(e,"Object")}function getInternalData(e){let t="htmx-internal-data",n=e[t];return n||(n=e[t]={}),n}function toArray(e){let t=[];if(e)for(let n=0;n<e.length;n++)t.push(e[n]);return t}function forEach(e,t){if(e)for(let n=0;n<e.length;n++)t(e[n])}function isScrolledIntoView(e){let t=e.getBoundingClientRect(),n=t.top,r=t.bottom;return n<window.innerHeight&&r>=0}function bodyContains(e){return e.getRootNode({composed:!0})===document}function splitOnWhitespace(e){return e.trim().split(/\s+/)}function mergeObjects(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function parseJSON(e){try{return JSON.parse(e)}catch(t){return logError(t),null}}function canAccessLocalStorage(){let e="htmx:sessionStorageTest";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch{return!1}}function normalizePath(e){let t=new URL(e,"http://x");return t&&(e=t.pathname+t.search),e!="/"&&(e=e.replace(/\/+$/,"")),e}function internalEval(str){return maybeEval(getDocument().body,function(){return eval(str)})}function onLoadHelper(e){return htmx.on("htmx:load",function(n){e(n.detail.elt)})}function logAll(){htmx.logger=function(e,t,n){console&&console.log(t,e,n)}}function logNone(){htmx.logger=null}function find(e,t){return typeof e!="string"?e.querySelector(t):find(getDocument(),e)}function findAll(e,t){return typeof e!="string"?e.querySelectorAll(t):findAll(getDocument(),e)}function getWindow(){return window}function removeElement(e,t){e=resolveTarget(e),t?getWindow().setTimeout(function(){removeElement(e),e=null},t):parentElt(e).removeChild(e)}function asElement(e){return e instanceof Element?e:null}function asHtmlElement(e){return e instanceof HTMLElement?e:null}function asString(e){return typeof e=="string"?e:null}function asParentNode(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function addClassToElement(e,t,n){e=asElement(resolveTarget(e)),e&&(n?getWindow().setTimeout(function(){addClassToElement(e,t),e=null},n):e.classList&&e.classList.add(t))}function removeClassFromElement(e,t,n){let r=asElement(resolveTarget(e));r&&(n?getWindow().setTimeout(function(){removeClassFromElement(r,t),r=null},n):r.classList&&(r.classList.remove(t),r.classList.length===0&&r.removeAttribute("class")))}function toggleClassOnElement(e,t){e=resolveTarget(e),e.classList.toggle(t)}function takeClassForElement(e,t){e=resolveTarget(e),forEach(e.parentElement.children,function(n){removeClassFromElement(n,t)}),addClassToElement(asElement(e),t)}function closest(e,t){return e=asElement(resolveTarget(e)),e?e.closest(t):null}function startsWith(e,t){return e.substring(0,t.length)===t}function endsWith(e,t){return e.substring(e.length-t.length)===t}function normalizeSelector(e){let t=e.trim();return startsWith(t,"<")&&endsWith(t,"/>")?t.substring(1,t.length-2):t}function querySelectorAllExt(e,t,n){if(t.indexOf("global ")===0)return querySelectorAllExt(e,t.slice(7),!0);e=resolveTarget(e);let r=[];{let s=0,a=0;for(let l=0;l<t.length;l++){let c=t[l];if(c===","&&s===0){r.push(t.substring(a,l)),a=l+1;continue}c==="<"?s++:c==="/"&&l<t.length-1&&t[l+1]===">"&&s--}a<t.length&&r.push(t.substring(a))}let o=[],i=[];for(;r.length>0;){let s=normalizeSelector(r.shift()),a;s.indexOf("closest ")===0?a=closest(asElement(e),normalizeSelector(s.slice(8))):s.indexOf("find ")===0?a=find(asParentNode(e),normalizeSelector(s.slice(5))):s==="next"||s==="nextElementSibling"?a=asElement(e).nextElementSibling:s.indexOf("next ")===0?a=scanForwardQuery(e,normalizeSelector(s.slice(5)),!!n):s==="previous"||s==="previousElementSibling"?a=asElement(e).previousElementSibling:s.indexOf("previous ")===0?a=scanBackwardsQuery(e,normalizeSelector(s.slice(9)),!!n):s==="document"?a=document:s==="window"?a=window:s==="body"?a=document.body:s==="root"?a=getRootNode(e,!!n):s==="host"?a=e.getRootNode().host:i.push(s),a&&o.push(a)}if(i.length>0){let s=i.join(","),a=asParentNode(getRootNode(e,!!n));o.push(...toArray(a.querySelectorAll(s)))}return o}var scanForwardQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=0;o<r.length;o++){let i=r[o];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING)return i}},scanBackwardsQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=r.length-1;o>=0;o--){let i=r[o];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING)return i}};function querySelectorExt(e,t){return typeof e!="string"?querySelectorAllExt(e,t)[0]:querySelectorAllExt(getDocument().body,e)[0]}function resolveTarget(e,t){return typeof e=="string"?find(asParentNode(t)||document,e):e}function processEventArgs(e,t,n,r){return isFunction(t)?{target:getDocument().body,event:asString(e),listener:t,options:n}:{target:resolveTarget(e),event:asString(t),listener:n,options:r}}function addEventListenerImpl(e,t,n,r){return ready(function(){let i=processEventArgs(e,t,n,r);i.target.addEventListener(i.event,i.listener,i.options)}),isFunction(t)?t:n}function removeEventListenerImpl(e,t,n){return ready(function(){let r=processEventArgs(e,t,n);r.target.removeEventListener(r.event,r.listener)}),isFunction(t)?t:n}let DUMMY_ELT=getDocument().createElement("output");function findAttributeTargets(e,t){let n=getClosestAttributeValue(e,t);if(n){if(n==="this")return[findThisElement(e,t)];{let r=querySelectorAllExt(e,n);if(/(^|,)(\s*)inherit(\s*)($|,)/.test(n)){let i=asElement(getClosestMatch(e,function(s){return s!==e&&hasAttribute(asElement(s),t)}));i&&r.push(...findAttributeTargets(i,t))}return r.length===0?(logError('The selector "'+n+'" on '+t+" returned no matches!"),[DUMMY_ELT]):r}}}function findThisElement(e,t){return asElement(getClosestMatch(e,function(n){return getAttributeValue(asElement(n),t)!=null}))}function getTarget(e){let t=getClosestAttributeValue(e,"hx-target");return t?t==="this"?findThisElement(e,"hx-target"):querySelectorExt(e,t):getInternalData(e).boosted?getDocument().body:e}function shouldSettleAttribute(e){return htmx.config.attributesToSettle.includes(e)}function cloneAttributes(e,t){forEach(Array.from(e.attributes),function(n){!t.hasAttribute(n.name)&&shouldSettleAttribute(n.name)&&e.removeAttribute(n.name)}),forEach(t.attributes,function(n){shouldSettleAttribute(n.name)&&e.setAttribute(n.name,n.value)})}function isInlineSwap(e,t){let n=getExtensions(t);for(let r=0;r<n.length;r++){let o=n[r];try{if(o.isInlineSwap(e))return!0}catch(i){logError(i)}}return e==="outerHTML"}function oobSwap(e,t,n,r){r=r||getDocument();let o="#"+CSS.escape(getRawAttribute(t,"id")),i="outerHTML";e==="true"||(e.indexOf(":")>0?(i=e.substring(0,e.indexOf(":")),o=e.substring(e.indexOf(":")+1)):i=e),t.removeAttribute("hx-swap-oob"),t.removeAttribute("data-hx-swap-oob");let s=querySelectorAllExt(r,o,!1);return s.length?(forEach(s,function(a){let l,c=t.cloneNode(!0);l=getDocument().createDocumentFragment(),l.appendChild(c),isInlineSwap(i,a)||(l=asParentNode(c));let h={shouldSwap:!0,target:a,fragment:l};triggerEvent(a,"htmx:oobBeforeSwap",h)&&(a=h.target,h.shouldSwap&&(handlePreservedElements(l),swapWithStyle(i,a,a,l,n),restorePreservedElements()),forEach(n.elts,function(u){triggerEvent(u,"htmx:oobAfterSwap",h)}))}),t.parentNode.removeChild(t)):(t.parentNode.removeChild(t),triggerErrorEvent(getDocument().body,"htmx:oobErrorNoTarget",{content:t})),e}function restorePreservedElements(){let e=find("#--htmx-preserve-pantry--");if(e){for(let t of[...e.children]){let n=find("#"+t.id);n.parentNode.moveBefore(t,n),n.remove()}e.remove()}}function handlePreservedElements(e){forEach(findAll(e,"[hx-preserve], [data-hx-preserve]"),function(t){let n=getAttributeValue(t,"id"),r=getDocument().getElementById(n);if(r!=null)if(t.moveBefore){let o=find("#--htmx-preserve-pantry--");o==null&&(getDocument().body.insertAdjacentHTML("afterend","<div id='--htmx-preserve-pantry--'></div>"),o=find("#--htmx-preserve-pantry--")),o.moveBefore(r,null)}else t.parentNode.replaceChild(r,t)})}function handleAttributes(e,t,n){forEach(t.querySelectorAll("[id]"),function(r){let o=getRawAttribute(r,"id");if(o&&o.length>0){let i=o.replace("'","\\'"),s=r.tagName.replace(":","\\:"),a=asParentNode(e),l=a&&a.querySelector(s+"[id='"+i+"']");if(l&&l!==a){let c=r.cloneNode();cloneAttributes(r,l),n.tasks.push(function(){cloneAttributes(r,c)})}}})}function makeAjaxLoadTask(e){return function(){removeClassFromElement(e,htmx.config.addedClass),processNode(asElement(e)),processFocus(asParentNode(e)),triggerEvent(e,"htmx:load")}}function processFocus(e){let t="[autofocus]",n=asHtmlElement(matches(e,t)?e:e.querySelector(t));n?.focus()}function insertNodesBefore(e,t,n,r){for(handleAttributes(e,n,r);n.childNodes.length>0;){let o=n.firstChild;addClassToElement(asElement(o),htmx.config.addedClass),e.insertBefore(o,t),o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE&&r.tasks.push(makeAjaxLoadTask(o))}}function stringHash(e,t){let n=0;for(;n<e.length;)t=(t<<5)-t+e.charCodeAt(n++)|0;return t}function attributeHash(e){let t=0;for(let n=0;n<e.attributes.length;n++){let r=e.attributes[n];r.value&&(t=stringHash(r.name,t),t=stringHash(r.value,t))}return t}function deInitOnHandlers(e){let t=getInternalData(e);if(t.onHandlers){for(let n=0;n<t.onHandlers.length;n++){let r=t.onHandlers[n];removeEventListenerImpl(e,r.event,r.listener)}delete t.onHandlers}}function deInitNode(e){let t=getInternalData(e);t.timeout&&clearTimeout(t.timeout),t.listenerInfos&&forEach(t.listenerInfos,function(n){n.on&&removeEventListenerImpl(n.on,n.trigger,n.listener)}),deInitOnHandlers(e),forEach(Object.keys(t),function(n){n!=="firstInitCompleted"&&delete t[n]})}function cleanUpElement(e){triggerEvent(e,"htmx:beforeCleanupElement"),deInitNode(e),forEach(e.children,function(t){cleanUpElement(t)})}function swapOuterHTML(e,t,n){if(e.tagName==="BODY")return swapInnerHTML(e,t,n);let r,o=e.previousSibling,i=parentElt(e);if(i){for(insertNodesBefore(i,e,t,n),o==null?r=i.firstChild:r=o.nextSibling,n.elts=n.elts.filter(function(s){return s!==e});r&&r!==e;)r instanceof Element&&n.elts.push(r),r=r.nextSibling;cleanUpElement(e),e.remove()}}function swapAfterBegin(e,t,n){return insertNodesBefore(e,e.firstChild,t,n)}function swapBeforeBegin(e,t,n){return insertNodesBefore(parentElt(e),e,t,n)}function swapBeforeEnd(e,t,n){return insertNodesBefore(e,null,t,n)}function swapAfterEnd(e,t,n){return insertNodesBefore(parentElt(e),e.nextSibling,t,n)}function swapDelete(e){cleanUpElement(e);let t=parentElt(e);if(t)return t.removeChild(e)}function swapInnerHTML(e,t,n){let r=e.firstChild;if(insertNodesBefore(e,r,t,n),r){for(;r.nextSibling;)cleanUpElement(r.nextSibling),e.removeChild(r.nextSibling);cleanUpElement(r),e.removeChild(r)}}function swapWithStyle(e,t,n,r,o){switch(e){case"none":return;case"outerHTML":swapOuterHTML(n,r,o);return;case"afterbegin":swapAfterBegin(n,r,o);return;case"beforebegin":swapBeforeBegin(n,r,o);return;case"beforeend":swapBeforeEnd(n,r,o);return;case"afterend":swapAfterEnd(n,r,o);return;case"delete":swapDelete(n);return;default:var i=getExtensions(t);for(let s=0;s<i.length;s++){let a=i[s];try{let l=a.handleSwap(e,n,r,o);if(l){if(Array.isArray(l))for(let c=0;c<l.length;c++){let h=l[c];h.nodeType!==Node.TEXT_NODE&&h.nodeType!==Node.COMMENT_NODE&&o.tasks.push(makeAjaxLoadTask(h))}return}}catch(l){logError(l)}}e==="innerHTML"?swapInnerHTML(n,r,o):swapWithStyle(htmx.config.defaultSwapStyle,t,n,r,o)}}function findAndSwapOobElements(e,t,n){var r=findAll(e,"[hx-swap-oob], [data-hx-swap-oob]");return forEach(r,function(o){if(htmx.config.allowNestedOobSwaps||o.parentElement===null){let i=getAttributeValue(o,"hx-swap-oob");i!=null&&oobSwap(i,o,t,n)}else o.removeAttribute("hx-swap-oob"),o.removeAttribute("data-hx-swap-oob")}),r.length>0}function swap(e,t,n,r){r||(r={});let o=null,i=null,s=function(){maybeCall(r.beforeSwapCallback),e=resolveTarget(e);let c=r.contextElement?getRootNode(r.contextElement,!1):getDocument(),h=document.activeElement,u={};u={elt:h,start:h?h.selectionStart:null,end:h?h.selectionEnd:null};let f=makeSettleInfo(e);if(n.swapStyle==="textContent")e.textContent=t;else{let d=makeFragment(t);if(f.title=r.title||d.title,r.historyRequest&&(d=d.querySelector("[hx-history-elt],[data-hx-history-elt]")||d),r.selectOOB){let y=r.selectOOB.split(",");for(let m=0;m<y.length;m++){let x=y[m].split(":",2),b=x[0].trim();b.indexOf("#")===0&&(b=b.substring(1));let E=x[1]||"true",g=d.querySelector("#"+b);g&&oobSwap(E,g,f,c)}}if(findAndSwapOobElements(d,f,c),forEach(findAll(d,"template"),function(y){y.content&&findAndSwapOobElements(y.content,f,c)&&y.remove()}),r.select){let y=getDocument().createDocumentFragment();forEach(d.querySelectorAll(r.select),function(m){y.appendChild(m)}),d=y}handlePreservedElements(d),swapWithStyle(n.swapStyle,r.contextElement,e,d,f),restorePreservedElements()}if(u.elt&&!bodyContains(u.elt)&&getRawAttribute(u.elt,"id")){let d=document.getElementById(getRawAttribute(u.elt,"id")),y={preventScroll:n.focusScroll!==void 0?!n.focusScroll:!htmx.config.defaultFocusScroll};if(d){if(u.start&&d.setSelectionRange)try{d.setSelectionRange(u.start,u.end)}catch{}d.focus(y)}}e.classList.remove(htmx.config.swappingClass),forEach(f.elts,function(d){d.classList&&d.classList.add(htmx.config.settlingClass),triggerEvent(d,"htmx:afterSwap",r.eventInfo)}),maybeCall(r.afterSwapCallback),n.ignoreTitle||handleTitle(f.title);let v=function(){if(forEach(f.tasks,function(d){d.call()}),forEach(f.elts,function(d){d.classList&&d.classList.remove(htmx.config.settlingClass),triggerEvent(d,"htmx:afterSettle",r.eventInfo)}),r.anchor){let d=asElement(resolveTarget("#"+r.anchor));d&&d.scrollIntoView({block:"start",behavior:"auto"})}updateScrollState(f.elts,n),maybeCall(r.afterSettleCallback),maybeCall(o)};n.settleDelay>0?getWindow().setTimeout(v,n.settleDelay):v()},a=htmx.config.globalViewTransitions;n.hasOwnProperty("transition")&&(a=n.transition);let l=r.contextElement||getDocument();if(a&&triggerEvent(l,"htmx:beforeTransition",r.eventInfo)&&typeof Promise<"u"&&document.startViewTransition){let c=new Promise(function(u,f){o=u,i=f}),h=s;s=function(){document.startViewTransition(function(){return h(),c})}}try{n?.swapDelay&&n.swapDelay>0?getWindow().setTimeout(s,n.swapDelay):s()}catch(c){throw triggerErrorEvent(l,"htmx:swapError",r.eventInfo),maybeCall(i),c}}function handleTriggerHeader(e,t,n){let r=e.getResponseHeader(t);if(r.indexOf("{")===0){let o=parseJSON(r);for(let i in o)if(o.hasOwnProperty(i)){let s=o[i];isRawObject(s)?n=s.target!==void 0?s.target:n:s={value:s},triggerEvent(n,i,s)}}else{let o=r.split(",");for(let i=0;i<o.length;i++)triggerEvent(n,o[i].trim(),[])}}let WHITESPACE=/\s/,WHITESPACE_OR_COMMA=/[\s,]/,SYMBOL_START=/[_$a-zA-Z]/,SYMBOL_CONT=/[_$a-zA-Z0-9]/,STRINGISH_START=['"',"'","/"],NOT_WHITESPACE=/[^\s]/,COMBINED_SELECTOR_START=/[{(]/,COMBINED_SELECTOR_END=/[})]/;function tokenizeString(e){let t=[],n=0;for(;n<e.length;){if(SYMBOL_START.exec(e.charAt(n))){for(var r=n;SYMBOL_CONT.exec(e.charAt(n+1));)n++;t.push(e.substring(r,n+1))}else if(STRINGISH_START.indexOf(e.charAt(n))!==-1){let o=e.charAt(n);var r=n;for(n++;n<e.length&&e.charAt(n)!==o;)e.charAt(n)==="\\"&&n++,n++;t.push(e.substring(r,n+1))}else{let o=e.charAt(n);t.push(o)}n++}return t}function isPossibleRelativeReference(e,t,n){return SYMBOL_START.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function maybeGenerateConditional(e,t,n){if(t[0]==="["){t.shift();let r=1,o=" return (function("+n+"){ return (",i=null;for(;t.length>0;){let s=t[0];if(s==="]"){if(r--,r===0){i===null&&(o=o+"true"),t.shift(),o+=")})";try{let a=maybeEval(e,function(){return Function(o)()},function(){return!0});return a.source=o,a}catch(a){return triggerErrorEvent(getDocument().body,"htmx:syntax:error",{error:a,source:o}),null}}}else s==="["&&r++;isPossibleRelativeReference(s,i,n)?o+="(("+n+"."+s+") ? ("+n+"."+s+") : (window."+s+"))":o=o+s,i=t.shift()}}}function consumeUntil(e,t){let n="";for(;e.length>0&&!t.test(e[0]);)n+=e.shift();return n}function consumeCSSSelector(e){let t;return e.length>0&&COMBINED_SELECTOR_START.test(e[0])?(e.shift(),t=consumeUntil(e,COMBINED_SELECTOR_END).trim(),e.shift()):t=consumeUntil(e,WHITESPACE_OR_COMMA),t}let INPUT_SELECTOR="input, textarea, select";function parseAndCacheTrigger(e,t,n){let r=[],o=tokenizeString(t);do{consumeUntil(o,NOT_WHITESPACE);let a=o.length,l=consumeUntil(o,/[,\[\s]/);if(l!=="")if(l==="every"){let c={trigger:"every"};consumeUntil(o,NOT_WHITESPACE),c.pollInterval=parseInterval(consumeUntil(o,/[,\[\s]/)),consumeUntil(o,NOT_WHITESPACE);var i=maybeGenerateConditional(e,o,"event");i&&(c.eventFilter=i),r.push(c)}else{let c={trigger:l};var i=maybeGenerateConditional(e,o,"event");for(i&&(c.eventFilter=i),consumeUntil(o,NOT_WHITESPACE);o.length>0&&o[0]!==",";){let u=o.shift();if(u==="changed")c.changed=!0;else if(u==="once")c.once=!0;else if(u==="consume")c.consume=!0;else if(u==="delay"&&o[0]===":")o.shift(),c.delay=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA));else if(u==="from"&&o[0]===":"){if(o.shift(),COMBINED_SELECTOR_START.test(o[0]))var s=consumeCSSSelector(o);else{var s=consumeUntil(o,WHITESPACE_OR_COMMA);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();let v=consumeCSSSelector(o);v.length>0&&(s+=" "+v)}}c.from=s}else u==="target"&&o[0]===":"?(o.shift(),c.target=consumeCSSSelector(o)):u==="throttle"&&o[0]===":"?(o.shift(),c.throttle=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA))):u==="queue"&&o[0]===":"?(o.shift(),c.queue=consumeUntil(o,WHITESPACE_OR_COMMA)):u==="root"&&o[0]===":"?(o.shift(),c[u]=consumeCSSSelector(o)):u==="threshold"&&o[0]===":"?(o.shift(),c[u]=consumeUntil(o,WHITESPACE_OR_COMMA)):triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()});consumeUntil(o,NOT_WHITESPACE)}r.push(c)}o.length===a&&triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()}),consumeUntil(o,NOT_WHITESPACE)}while(o[0]===","&&o.shift());return n&&(n[t]=r),r}function getTriggerSpecs(e){let t=getAttributeValue(e,"hx-trigger"),n=[];if(t){let r=htmx.config.triggerSpecsCache;n=r&&r[t]||parseAndCacheTrigger(e,t,r)}return n.length>0?n:matches(e,"form")?[{trigger:"submit"}]:matches(e,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:matches(e,INPUT_SELECTOR)?[{trigger:"change"}]:[{trigger:"click"}]}function cancelPolling(e){getInternalData(e).cancelled=!0}function processPolling(e,t,n){let r=getInternalData(e);r.timeout=getWindow().setTimeout(function(){bodyContains(e)&&r.cancelled!==!0&&(maybeFilterEvent(n,e,makeEvent("hx:poll:trigger",{triggerSpec:n,target:e}))||t(e),processPolling(e,t,n))},n.pollInterval)}function isLocalLink(e){return location.hostname===e.hostname&&getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")!==0}function eltIsDisabled(e){return closest(e,htmx.config.disableSelector)}function boostElement(e,t,n){if(e instanceof HTMLAnchorElement&&isLocalLink(e)&&(e.target===""||e.target==="_self")||e.tagName==="FORM"&&String(getRawAttribute(e,"method")).toLowerCase()!=="dialog"){t.boosted=!0;let r,o;if(e.tagName==="A")r="get",o=getRawAttribute(e,"href");else{let i=getRawAttribute(e,"method");r=i?i.toLowerCase():"get",o=getRawAttribute(e,"action"),(o==null||o==="")&&(o=location.href),r==="get"&&o.includes("?")&&(o=o.replace(/\?[^#]+/,""))}n.forEach(function(i){addEventListener(e,function(s,a){let l=asElement(s);if(eltIsDisabled(l)){cleanUpElement(l);return}issueAjaxRequest(r,o,l,a)},t,i,!0)})}}function shouldCancel(e,t){if(e.type==="submit"&&t.tagName==="FORM")return!0;if(e.type==="click"){let n=t.closest('input[type="submit"], button');if(n&&n.form&&n.type==="submit")return!0;let r=t.closest("a"),o=/^#.+/;if(r&&r.href&&!o.test(r.getAttribute("href")))return!0}return!1}function ignoreBoostedAnchorCtrlClick(e,t){return getInternalData(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function maybeFilterEvent(e,t,n){let r=e.eventFilter;if(r)try{return r.call(t,n)!==!0}catch(o){let i=r.source;return triggerErrorEvent(getDocument().body,"htmx:eventFilter:error",{error:o,source:i}),!0}return!1}function addEventListener(e,t,n,r,o){let i=getInternalData(e),s;r.from?s=querySelectorAllExt(e,r.from):s=[e],r.changed&&("lastValue"in i||(i.lastValue=new WeakMap),s.forEach(function(a){i.lastValue.has(r)||i.lastValue.set(r,new WeakMap),i.lastValue.get(r).set(a,a.value)})),forEach(s,function(a){let l=function(c){if(!bodyContains(e)){a.removeEventListener(r.trigger,l);return}if(ignoreBoostedAnchorCtrlClick(e,c)||((o||shouldCancel(c,a))&&c.preventDefault(),maybeFilterEvent(r,e,c)))return;let h=getInternalData(c);if(h.triggerSpec=r,h.handledFor==null&&(h.handledFor=[]),h.handledFor.indexOf(e)<0){if(h.handledFor.push(e),r.consume&&c.stopPropagation(),r.target&&c.target&&!matches(asElement(c.target),r.target))return;if(r.once){if(i.triggeredOnce)return;i.triggeredOnce=!0}if(r.changed){let u=c.target,f=u.value,v=i.lastValue.get(r);if(v.has(u)&&v.get(u)===f)return;v.set(u,f)}if(i.delayed&&clearTimeout(i.delayed),i.throttle)return;r.throttle>0?i.throttle||(triggerEvent(e,"htmx:trigger"),t(e,c),i.throttle=getWindow().setTimeout(function(){i.throttle=null},r.throttle)):r.delay>0?i.delayed=getWindow().setTimeout(function(){triggerEvent(e,"htmx:trigger"),t(e,c)},r.delay):(triggerEvent(e,"htmx:trigger"),t(e,c))}};n.listenerInfos==null&&(n.listenerInfos=[]),n.listenerInfos.push({trigger:r.trigger,listener:l,on:a}),a.addEventListener(r.trigger,l)})}let windowIsScrolling=!1,scrollHandler=null;function initScrollHandler(){scrollHandler||(scrollHandler=function(){windowIsScrolling=!0},window.addEventListener("scroll",scrollHandler),window.addEventListener("resize",scrollHandler),setInterval(function(){windowIsScrolling&&(windowIsScrolling=!1,forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){maybeReveal(e)}))},200))}function maybeReveal(e){!hasAttribute(e,"data-hx-revealed")&&isScrolledIntoView(e)&&(e.setAttribute("data-hx-revealed","true"),getInternalData(e).initHash?triggerEvent(e,"revealed"):e.addEventListener("htmx:afterProcessNode",function(){triggerEvent(e,"revealed")},{once:!0}))}function loadImmediately(e,t,n,r){let o=function(){n.loaded||(n.loaded=!0,triggerEvent(e,"htmx:trigger"),t(e))};r>0?getWindow().setTimeout(o,r):o()}function processVerbs(e,t,n){let r=!1;return forEach(VERBS,function(o){if(hasAttribute(e,"hx-"+o)){let i=getAttributeValue(e,"hx-"+o);r=!0,t.path=i,t.verb=o,n.forEach(function(s){addTriggerHandler(e,s,t,function(a,l){let c=asElement(a);if(eltIsDisabled(c)){cleanUpElement(c);return}issueAjaxRequest(o,i,c,l)})})}}),r}function addTriggerHandler(e,t,n,r){if(t.trigger==="revealed")initScrollHandler(),addEventListener(e,r,n,t),maybeReveal(asElement(e));else if(t.trigger==="intersect"){let o={};t.root&&(o.root=querySelectorExt(e,t.root)),t.threshold&&(o.threshold=parseFloat(t.threshold)),new IntersectionObserver(function(s){for(let a=0;a<s.length;a++)if(s[a].isIntersecting){triggerEvent(e,"intersect");break}},o).observe(asElement(e)),addEventListener(asElement(e),r,n,t)}else!n.firstInitCompleted&&t.trigger==="load"?maybeFilterEvent(t,e,makeEvent("load",{elt:e}))||loadImmediately(asElement(e),r,n,t.delay):t.pollInterval>0?(n.polling=!0,processPolling(asElement(e),r,t)):addEventListener(e,r,n,t)}function shouldProcessHxOn(e){let t=asElement(e);if(!t)return!1;let n=t.attributes;for(let r=0;r<n.length;r++){let o=n[r].name;if(startsWith(o,"hx-on:")||startsWith(o,"data-hx-on:")||startsWith(o,"hx-on-")||startsWith(o,"data-hx-on-"))return!0}return!1}let HX_ON_QUERY=new XPathEvaluator().createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function processHXOnRoot(e,t){shouldProcessHxOn(e)&&t.push(asElement(e));let n=HX_ON_QUERY.evaluate(e),r=null;for(;r=n.iterateNext();)t.push(asElement(r))}function findHxOnWildcardElements(e){let t=[];if(e instanceof DocumentFragment)for(let n of e.childNodes)processHXOnRoot(n,t);else processHXOnRoot(e,t);return t}function findElementsToProcess(e){if(e.querySelectorAll){let n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]",r=[];for(let i in extensions){let s=extensions[i];if(s.getSelectors){var t=s.getSelectors();t&&r.push(t)}}return e.querySelectorAll(VERB_SELECTOR+n+", form, [type='submit'], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(i=>", "+i).join(""))}else return[]}function maybeSetLastButtonClicked(e){let t=getTargetButton(e.target),n=getRelatedFormData(e);n&&(n.lastButtonClicked=t)}function maybeUnsetLastButtonClicked(e){let t=getRelatedFormData(e);t&&(t.lastButtonClicked=null)}function getTargetButton(e){return closest(asElement(e),"button, input[type='submit']")}function getRelatedForm(e){return e.form||closest(e,"form")}function getRelatedFormData(e){let t=getTargetButton(e.target);if(!t)return;let n=getRelatedForm(t);if(n)return getInternalData(n)}function initButtonTracking(e){e.addEventListener("click",maybeSetLastButtonClicked),e.addEventListener("focusin",maybeSetLastButtonClicked),e.addEventListener("focusout",maybeUnsetLastButtonClicked)}function addHxOnEventHandler(e,t,n){let r=getInternalData(e);Array.isArray(r.onHandlers)||(r.onHandlers=[]);let o,i=function(s){maybeEval(e,function(){eltIsDisabled(e)||(o||(o=new Function("event",n)),o.call(e,s))})};e.addEventListener(t,i),r.onHandlers.push({event:t,listener:i})}function processHxOnWildcard(e){deInitOnHandlers(e);for(let t=0;t<e.attributes.length;t++){let n=e.attributes[t].name,r=e.attributes[t].value;if(startsWith(n,"hx-on")||startsWith(n,"data-hx-on")){let o=n.indexOf("-on")+3,i=n.slice(o,o+1);if(i==="-"||i===":"){let s=n.slice(o+1);startsWith(s,":")?s="htmx"+s:startsWith(s,"-")?s="htmx:"+s.slice(1):startsWith(s,"htmx-")&&(s="htmx:"+s.slice(5)),addHxOnEventHandler(e,s,r)}}}}function initNode(e){triggerEvent(e,"htmx:beforeProcessNode");let t=getInternalData(e),n=getTriggerSpecs(e);processVerbs(e,t,n)||(getClosestAttributeValue(e,"hx-boost")==="true"?boostElement(e,t,n):hasAttribute(e,"hx-trigger")&&n.forEach(function(o){addTriggerHandler(e,o,t,function(){})})),(e.tagName==="FORM"||getRawAttribute(e,"type")==="submit"&&hasAttribute(e,"form"))&&initButtonTracking(e),t.firstInitCompleted=!0,triggerEvent(e,"htmx:afterProcessNode")}function maybeDeInitAndHash(e){if(!(e instanceof Element))return!1;let t=getInternalData(e),n=attributeHash(e);return t.initHash!==n?(deInitNode(e),t.initHash=n,!0):!1}function processNode(e){if(e=resolveTarget(e),eltIsDisabled(e)){cleanUpElement(e);return}let t=[];maybeDeInitAndHash(e)&&t.push(e),forEach(findElementsToProcess(e),function(n){if(eltIsDisabled(n)){cleanUpElement(n);return}maybeDeInitAndHash(n)&&t.push(n)}),forEach(findHxOnWildcardElements(e),processHxOnWildcard),forEach(t,initNode)}function kebabEventName(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function makeEvent(e,t){return new CustomEvent(e,{bubbles:!0,cancelable:!0,composed:!0,detail:t})}function triggerErrorEvent(e,t,n){triggerEvent(e,t,mergeObjects({error:t},n))}function ignoreEventForLogging(e){return e==="htmx:afterProcessNode"}function withExtensions(e,t,n){forEach(getExtensions(e,[],n),function(r){try{t(r)}catch(o){logError(o)}})}function logError(e){console.error(e)}function triggerEvent(e,t,n){e=resolveTarget(e),n==null&&(n={}),n.elt=e;let r=makeEvent(t,n);htmx.logger&&!ignoreEventForLogging(t)&&htmx.logger(e,t,n),n.error&&(logError(n.error),triggerEvent(e,"htmx:error",{errorInfo:n}));let o=e.dispatchEvent(r),i=kebabEventName(t);if(o&&i!==t){let s=makeEvent(i,r.detail);o=o&&e.dispatchEvent(s)}return withExtensions(asElement(e),function(s){o=o&&s.onEvent(t,r)!==!1&&!r.defaultPrevented}),o}let currentPathForHistory;function setCurrentPathForHistory(e){currentPathForHistory=e,canAccessLocalStorage()&&sessionStorage.setItem("htmx-current-path-for-history",e)}setCurrentPathForHistory(location.pathname+location.search);function getHistoryElement(){return getDocument().querySelector("[hx-history-elt],[data-hx-history-elt]")||getDocument().body}function saveToHistoryCache(e,t){if(!canAccessLocalStorage())return;let n=cleanInnerHtmlForHistory(t),r=getDocument().title,o=window.scrollY;if(htmx.config.historyCacheSize<=0){sessionStorage.removeItem("htmx-history-cache");return}e=normalizePath(e);let i=parseJSON(sessionStorage.getItem("htmx-history-cache"))||[];for(let a=0;a<i.length;a++)if(i[a].url===e){i.splice(a,1);break}let s={url:e,content:n,title:r,scroll:o};for(triggerEvent(getDocument().body,"htmx:historyItemCreated",{item:s,cache:i}),i.push(s);i.length>htmx.config.historyCacheSize;)i.shift();for(;i.length>0;)try{sessionStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(a){triggerErrorEvent(getDocument().body,"htmx:historyCacheError",{cause:a,cache:i}),i.shift()}}function getCachedHistory(e){if(!canAccessLocalStorage())return null;e=normalizePath(e);let t=parseJSON(sessionStorage.getItem("htmx-history-cache"))||[];for(let n=0;n<t.length;n++)if(t[n].url===e)return t[n];return null}function cleanInnerHtmlForHistory(e){let t=htmx.config.requestClass,n=e.cloneNode(!0);return forEach(findAll(n,"."+t),function(r){removeClassFromElement(r,t)}),forEach(findAll(n,"[data-disabled-by-htmx]"),function(r){r.removeAttribute("disabled")}),n.innerHTML}function saveCurrentPageToHistory(){let e=getHistoryElement(),t=currentPathForHistory;canAccessLocalStorage()&&(t=sessionStorage.getItem("htmx-current-path-for-history")),t=t||location.pathname+location.search,getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]')||(triggerEvent(getDocument().body,"htmx:beforeHistorySave",{path:t,historyElt:e}),saveToHistoryCache(t,e)),htmx.config.historyEnabled&&history.replaceState({htmx:!0},getDocument().title,location.href)}function pushUrlIntoHistory(e){htmx.config.getCacheBusterParam&&(e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,""),(endsWith(e,"&")||endsWith(e,"?"))&&(e=e.slice(0,-1))),htmx.config.historyEnabled&&history.pushState({htmx:!0},"",e),setCurrentPathForHistory(e)}function replaceUrlInHistory(e){htmx.config.historyEnabled&&history.replaceState({htmx:!0},"",e),setCurrentPathForHistory(e)}function settleImmediately(e){forEach(e,function(t){t.call(void 0)})}function loadHistoryFromServer(e){let t=new XMLHttpRequest,n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0},r={path:e,xhr:t,historyElt:getHistoryElement(),swapSpec:n};t.open("GET",e,!0),htmx.config.historyRestoreAsHxRequest&&t.setRequestHeader("HX-Request","true"),t.setRequestHeader("HX-History-Restore-Request","true"),t.setRequestHeader("HX-Current-URL",location.href),t.onload=function(){this.status>=200&&this.status<400?(r.response=this.response,triggerEvent(getDocument().body,"htmx:historyCacheMissLoad",r),swap(r.historyElt,r.response,n,{contextElement:r.historyElt,historyRequest:!0}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,cacheMiss:!0,serverResponse:r.response})):triggerErrorEvent(getDocument().body,"htmx:historyCacheMissLoadError",r)},triggerEvent(getDocument().body,"htmx:historyCacheMiss",r)&&t.send()}function restoreHistory(e){saveCurrentPageToHistory(),e=e||location.pathname+location.search;let t=getCachedHistory(e);if(t){let n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0,scroll:t.scroll},r={path:e,item:t,historyElt:getHistoryElement(),swapSpec:n};triggerEvent(getDocument().body,"htmx:historyCacheHit",r)&&(swap(r.historyElt,t.content,n,{contextElement:r.historyElt,title:t.title}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",r))}else htmx.config.refreshOnHistoryMiss?htmx.location.reload(!0):loadHistoryFromServer(e)}function addRequestIndicatorClasses(e){let t=findAttributeTargets(e,"hx-indicator");return t==null&&(t=[e]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.classList.add.call(n.classList,htmx.config.requestClass)}),t}function disableElements(e){let t=findAttributeTargets(e,"hx-disabled-elt");return t==null&&(t=[]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.setAttribute("disabled",""),n.setAttribute("data-disabled-by-htmx","")}),t}function removeRequestIndicators(e,t){forEach(e.concat(t),function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||1)-1}),forEach(e,function(n){getInternalData(n).requestCount===0&&n.classList.remove.call(n.classList,htmx.config.requestClass)}),forEach(t,function(n){getInternalData(n).requestCount===0&&(n.removeAttribute("disabled"),n.removeAttribute("data-disabled-by-htmx"))})}function haveSeenNode(e,t){for(let n=0;n<e.length;n++)if(e[n].isSameNode(t))return!0;return!1}function shouldInclude(e){let t=e;return t.name===""||t.name==null||t.disabled||closest(t,"fieldset[disabled]")||t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"?!1:t.type==="checkbox"||t.type==="radio"?t.checked:!0}function addValueToFormData(e,t,n){e!=null&&t!=null&&(Array.isArray(t)?t.forEach(function(r){n.append(e,r)}):n.append(e,t))}function removeValueFromFormData(e,t,n){if(e!=null&&t!=null){let r=n.getAll(e);Array.isArray(t)?r=r.filter(o=>t.indexOf(o)<0):r=r.filter(o=>o!==t),n.delete(e),forEach(r,o=>n.append(e,o))}}function getValueFromInput(e){return e instanceof HTMLSelectElement&&e.multiple?toArray(e.querySelectorAll("option:checked")).map(function(t){return t.value}):e instanceof HTMLInputElement&&e.files?toArray(e.files):e.value}function processInputValue(e,t,n,r,o){if(!(r==null||haveSeenNode(e,r))){if(e.push(r),shouldInclude(r)){let i=getRawAttribute(r,"name");addValueToFormData(i,getValueFromInput(r),t),o&&validateElement(r,n)}r instanceof HTMLFormElement&&(forEach(r.elements,function(i){e.indexOf(i)>=0?removeValueFromFormData(i.name,getValueFromInput(i),t):e.push(i),o&&validateElement(i,n)}),new FormData(r).forEach(function(i,s){i instanceof File&&i.name===""||addValueToFormData(s,i,t)}))}}function validateElement(e,t){let n=e;n.willValidate&&(triggerEvent(n,"htmx:validation:validate"),n.checkValidity()||(triggerEvent(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})&&!t.length&&htmx.config.reportValidityOfForms&&n.reportValidity(),t.push({elt:n,message:n.validationMessage,validity:n.validity})))}function overrideFormData(e,t){for(let n of t.keys())e.delete(n);return t.forEach(function(n,r){e.append(r,n)}),e}function getInputValues(e,t){let n=[],r=new FormData,o=new FormData,i=[],s=getInternalData(e);s.lastButtonClicked&&!bodyContains(s.lastButtonClicked)&&(s.lastButtonClicked=null);let a=e instanceof HTMLFormElement&&e.noValidate!==!0||getAttributeValue(e,"hx-validate")==="true";if(s.lastButtonClicked&&(a=a&&s.lastButtonClicked.formNoValidate!==!0),t!=="get"&&processInputValue(n,o,i,getRelatedForm(e),a),processInputValue(n,r,i,e,a),s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&getRawAttribute(e,"type")==="submit"){let c=s.lastButtonClicked||e,h=getRawAttribute(c,"name");addValueToFormData(h,c.value,o)}let l=findAttributeTargets(e,"hx-include");return forEach(l,function(c){processInputValue(n,r,i,asElement(c),a),matches(c,"form")||forEach(asParentNode(c).querySelectorAll(INPUT_SELECTOR),function(h){processInputValue(n,r,i,h,a)})}),overrideFormData(r,o),{errors:i,formData:r,values:formDataProxy(r)}}function appendParam(e,t,n){e!==""&&(e+="&"),String(n)==="[object Object]"&&(n=JSON.stringify(n));let r=encodeURIComponent(n);return e+=encodeURIComponent(t)+"="+r,e}function urlEncode(e){e=formDataFromObject(e);let t="";return e.forEach(function(n,r){t=appendParam(t,r,n)}),t}function getHeaders(e,t,n){let r={"HX-Request":"true","HX-Trigger":getRawAttribute(e,"id"),"HX-Trigger-Name":getRawAttribute(e,"name"),"HX-Target":getAttributeValue(t,"id"),"HX-Current-URL":location.href};return getValuesForElement(e,"hx-headers",!1,r),n!==void 0&&(r["HX-Prompt"]=n),getInternalData(e).boosted&&(r["HX-Boosted"]="true"),r}function filterValues(e,t){let n=getClosestAttributeValue(t,"hx-params");if(n){if(n==="none")return new FormData;if(n==="*")return e;if(n.indexOf("not ")===0)return forEach(n.slice(4).split(","),function(r){r=r.trim(),e.delete(r)}),e;{let r=new FormData;return forEach(n.split(","),function(o){o=o.trim(),e.has(o)&&e.getAll(o).forEach(function(i){r.append(o,i)})}),r}}else return e}function isAnchorLink(e){return!!getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")>=0}function getSwapSpecification(e,t){let n=t||getClosestAttributeValue(e,"hx-swap"),r={swapStyle:getInternalData(e).boosted?"innerHTML":htmx.config.defaultSwapStyle,swapDelay:htmx.config.defaultSwapDelay,settleDelay:htmx.config.defaultSettleDelay};if(htmx.config.scrollIntoViewOnBoost&&getInternalData(e).boosted&&!isAnchorLink(e)&&(r.show="top"),n){let s=splitOnWhitespace(n);if(s.length>0)for(let a=0;a<s.length;a++){let l=s[a];if(l.indexOf("swap:")===0)r.swapDelay=parseInterval(l.slice(5));else if(l.indexOf("settle:")===0)r.settleDelay=parseInterval(l.slice(7));else if(l.indexOf("transition:")===0)r.transition=l.slice(11)==="true";else if(l.indexOf("ignoreTitle:")===0)r.ignoreTitle=l.slice(12)==="true";else if(l.indexOf("scroll:")===0){var o=l.slice(7).split(":");let h=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=h,r.scrollTarget=i}else if(l.indexOf("show:")===0){var o=l.slice(5).split(":");let u=o.pop();var i=o.length>0?o.join(":"):null;r.show=u,r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){let c=l.slice(13);r.focusScroll=c=="true"}else a==0?r.swapStyle=l:logError("Unknown modifier in hx-swap: "+l)}}return r}function usesFormData(e){return getClosestAttributeValue(e,"hx-encoding")==="multipart/form-data"||matches(e,"form")&&getRawAttribute(e,"enctype")==="multipart/form-data"}function encodeParamsForBody(e,t,n){let r=null;return withExtensions(t,function(o){r==null&&(r=o.encodeParameters(e,n,t))}),r??(usesFormData(t)?overrideFormData(new FormData,formDataFromObject(n)):urlEncode(n))}function makeSettleInfo(e){return{tasks:[],elts:[e]}}function updateScrollState(e,t){let n=e[0],r=e[e.length-1];if(t.scroll){var o=null;t.scrollTarget&&(o=asElement(querySelectorExt(n,t.scrollTarget))),t.scroll==="top"&&(n||o)&&(o=o||n,o.scrollTop=0),t.scroll==="bottom"&&(r||o)&&(o=o||r,o.scrollTop=o.scrollHeight),typeof t.scroll=="number"&&getWindow().setTimeout(function(){window.scrollTo(0,t.scroll)},0)}if(t.show){var o=null;if(t.showTarget){let s=t.showTarget;t.showTarget==="window"&&(s="body"),o=asElement(querySelectorExt(n,s))}t.show==="top"&&(n||o)&&(o=o||n,o.scrollIntoView({block:"start",behavior:htmx.config.scrollBehavior})),t.show==="bottom"&&(r||o)&&(o=o||r,o.scrollIntoView({block:"end",behavior:htmx.config.scrollBehavior}))}}function getValuesForElement(e,t,n,r,o){if(r==null&&(r={}),e==null)return r;let i=getAttributeValue(e,t);if(i){let s=i.trim(),a=n;if(s==="unset")return null;s.indexOf("javascript:")===0?(s=s.slice(11),a=!0):s.indexOf("js:")===0&&(s=s.slice(3),a=!0),s.indexOf("{")!==0&&(s="{"+s+"}");let l;a?l=maybeEval(e,function(){return o?Function("event","return ("+s+")").call(e,o):Function("return ("+s+")").call(e)},{}):l=parseJSON(s);for(let c in l)l.hasOwnProperty(c)&&r[c]==null&&(r[c]=l[c])}return getValuesForElement(asElement(parentElt(e)),t,n,r,o)}function maybeEval(e,t,n){return htmx.config.allowEval?t():(triggerErrorEvent(e,"htmx:evalDisallowedError"),n)}function getHXVarsForElement(e,t,n){return getValuesForElement(e,"hx-vars",!0,n,t)}function getHXValsForElement(e,t,n){return getValuesForElement(e,"hx-vals",!1,n,t)}function getExpressionVars(e,t){return mergeObjects(getHXVarsForElement(e,t),getHXValsForElement(e,t))}function safelySetHeaderValue(e,t,n){if(n!==null)try{e.setRequestHeader(t,n)}catch{e.setRequestHeader(t,encodeURIComponent(n)),e.setRequestHeader(t+"-URI-AutoEncoded","true")}}function getPathFromResponse(e){if(e.responseURL)try{let t=new URL(e.responseURL);return t.pathname+t.search}catch{triggerErrorEvent(getDocument().body,"htmx:badResponseUrl",{url:e.responseURL})}}function hasHeader(e,t){return t.test(e.getAllResponseHeaders())}function ajaxHelper(e,t,n){if(e=e.toLowerCase(),n){if(n instanceof Element||typeof n=="string")return issueAjaxRequest(e,t,null,null,{targetOverride:resolveTarget(n)||DUMMY_ELT,returnPromise:!0});{let r=resolveTarget(n.target);return(n.target&&!r||n.source&&!r&&!resolveTarget(n.source))&&(r=DUMMY_ELT),issueAjaxRequest(e,t,resolveTarget(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:r,swapOverride:n.swap,select:n.select,returnPromise:!0,push:n.push,replace:n.replace,selectOOB:n.selectOOB})}}else return issueAjaxRequest(e,t,null,null,{returnPromise:!0})}function hierarchyForElt(e){let t=[];for(;e;)t.push(e),e=e.parentElement;return t}function verifyPath(e,t,n){let r=new URL(t,location.protocol!=="about:"?location.href:window.origin),i=(location.protocol!=="about:"?location.origin:window.origin)===r.origin;return htmx.config.selfRequestsOnly&&!i?!1:triggerEvent(e,"htmx:validateUrl",mergeObjects({url:r,sameHost:i},n))}function formDataFromObject(e){if(e instanceof FormData)return e;let t=new FormData;for(let n in e)e.hasOwnProperty(n)&&(e[n]&&typeof e[n].forEach=="function"?e[n].forEach(function(r){t.append(n,r)}):typeof e[n]=="object"&&!(e[n]instanceof Blob)?t.append(n,JSON.stringify(e[n])):t.append(n,e[n]));return t}function formDataArrayProxy(e,t,n){return new Proxy(n,{get:function(r,o){return typeof o=="number"?r[o]:o==="length"?r.length:o==="push"?function(i){r.push(i),e.append(t,i)}:typeof r[o]=="function"?function(){r[o].apply(r,arguments),e.delete(t),r.forEach(function(i){e.append(t,i)})}:r[o]&&r[o].length===1?r[o][0]:r[o]},set:function(r,o,i){return r[o]=i,e.delete(t),r.forEach(function(s){e.append(t,s)}),!0}})}function formDataProxy(e){return new Proxy(e,{get:function(t,n){if(typeof n=="symbol"){let o=Reflect.get(t,n);return typeof o=="function"?function(){return o.apply(e,arguments)}:o}if(n==="toJSON")return()=>Object.fromEntries(e);if(n in t&&typeof t[n]=="function")return function(){return e[n].apply(e,arguments)};let r=e.getAll(n);if(r.length!==0)return r.length===1?r[0]:formDataArrayProxy(t,n,r)},set:function(t,n,r){return typeof n!="string"?!1:(t.delete(n),r&&typeof r.forEach=="function"?r.forEach(function(o){t.append(n,o)}):typeof r=="object"&&!(r instanceof Blob)?t.append(n,JSON.stringify(r)):t.append(n,r),!0)},deleteProperty:function(t,n){return typeof n=="string"&&t.delete(n),!0},ownKeys:function(t){return Reflect.ownKeys(Object.fromEntries(t))},getOwnPropertyDescriptor:function(t,n){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(t),n)}})}function issueAjaxRequest(e,t,n,r,o,i){let s=null,a=null;if(o=o??{},o.returnPromise&&typeof Promise<"u")var l=new Promise(function(p,w){s=p,a=w});n==null&&(n=getDocument().body);let c=o.handler||handleAjaxResponse,h=o.select||null;if(!bodyContains(n))return maybeCall(s),l;let u=o.targetOverride||asElement(getTarget(n));if(u==null||u==DUMMY_ELT)return triggerErrorEvent(n,"htmx:targetError",{target:getClosestAttributeValue(n,"hx-target")}),maybeCall(a),l;let f=getInternalData(n),v=f.lastButtonClicked;if(v){let p=getRawAttribute(v,"formaction");p!=null&&(t=p);let w=getRawAttribute(v,"formmethod");if(w!=null)if(VERBS.includes(w.toLowerCase()))e=w;else return maybeCall(s),l}let d=getClosestAttributeValue(n,"hx-confirm");if(i===void 0&&triggerEvent(n,"htmx:confirm",{target:u,elt:n,path:t,verb:e,triggeringEvent:r,etc:o,issueRequest:function(T){return issueAjaxRequest(e,t,n,r,o,!!T)},question:d})===!1)return maybeCall(s),l;let y=n,m=getClosestAttributeValue(n,"hx-sync"),x=null,b=!1;if(m){let p=m.split(":"),w=p[0].trim();if(w==="this"?y=findThisElement(n,"hx-sync"):y=asElement(querySelectorExt(n,w)),m=(p[1]||"drop").trim(),f=getInternalData(y),m==="drop"&&f.xhr&&f.abortable!==!0)return maybeCall(s),l;if(m==="abort"){if(f.xhr)return maybeCall(s),l;b=!0}else m==="replace"?triggerEvent(y,"htmx:abort"):m.indexOf("queue")===0&&(x=(m.split(" ")[1]||"last").trim())}if(f.xhr)if(f.abortable)triggerEvent(y,"htmx:abort");else{if(x==null){if(r){let p=getInternalData(r);p&&p.triggerSpec&&p.triggerSpec.queue&&(x=p.triggerSpec.queue)}x==null&&(x="last")}return f.queuedRequests==null&&(f.queuedRequests=[]),x==="first"&&f.queuedRequests.length===0?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):x==="all"?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):x==="last"&&(f.queuedRequests=[],f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)})),maybeCall(s),l}let E=new XMLHttpRequest;f.xhr=E,f.abortable=b;let g=function(){f.xhr=null,f.abortable=!1,f.queuedRequests!=null&&f.queuedRequests.length>0&&f.queuedRequests.shift()()},W=getClosestAttributeValue(n,"hx-prompt");if(W){var q=prompt(W);if(q===null||!triggerEvent(n,"htmx:prompt",{prompt:q,target:u}))return maybeCall(s),g(),l}if(d&&!i&&!confirm(d))return maybeCall(s),g(),l;let H=getHeaders(n,u,q);e!=="get"&&!usesFormData(n)&&(H["Content-Type"]="application/x-www-form-urlencoded"),o.headers&&(H=mergeObjects(H,o.headers));let X=getInputValues(n,e),R=X.errors,$=X.formData;o.values&&overrideFormData($,formDataFromObject(o.values));let re=formDataFromObject(getExpressionVars(n,r)),P=overrideFormData($,re),D=filterValues(P,n);htmx.config.getCacheBusterParam&&e==="get"&&D.set("org.htmx.cache-buster",getRawAttribute(u,"id")||"true"),(t==null||t==="")&&(t=location.href);let k=getValuesForElement(n,"hx-request"),J=getInternalData(n).boosted,I=htmx.config.methodsThatUseUrlParams.indexOf(e)>=0,S={boosted:J,useUrlParams:I,formData:D,parameters:formDataProxy(D),unfilteredFormData:P,unfilteredParameters:formDataProxy(P),headers:H,elt:n,target:u,verb:e,errors:R,withCredentials:o.credentials||k.credentials||htmx.config.withCredentials,timeout:o.timeout||k.timeout||htmx.config.timeout,path:t,triggeringEvent:r};if(!triggerEvent(n,"htmx:configRequest",S))return maybeCall(s),g(),l;if(t=S.path,e=S.verb,H=S.headers,D=formDataFromObject(S.parameters),R=S.errors,I=S.useUrlParams,R&&R.length>0)return triggerEvent(n,"htmx:validation:halted",S),maybeCall(s),g(),l;let z=t.split("#"),oe=z[0],M=z[1],A=t;if(I&&(A=oe,!D.keys().next().done&&(A.indexOf("?")<0?A+="?":A+="&",A+=urlEncode(D),M&&(A+="#"+M))),!verifyPath(n,A,S))return triggerErrorEvent(n,"htmx:invalidPath",S),maybeCall(a),g(),l;if(E.open(e.toUpperCase(),A,!0),E.overrideMimeType("text/html"),E.withCredentials=S.withCredentials,E.timeout=S.timeout,!k.noHeaders){for(let p in H)if(H.hasOwnProperty(p)){let w=H[p];safelySetHeaderValue(E,p,w)}}let C={xhr:E,target:u,requestConfig:S,etc:o,boosted:J,select:h,pathInfo:{requestPath:t,finalRequestPath:A,responsePath:null,anchor:M}};if(E.onload=function(){try{let p=hierarchyForElt(n);if(C.pathInfo.responsePath=getPathFromResponse(E),c(n,C),C.keepIndicators!==!0&&removeRequestIndicators(L,O),triggerEvent(n,"htmx:afterRequest",C),triggerEvent(n,"htmx:afterOnLoad",C),!bodyContains(n)){let w=null;for(;p.length>0&&w==null;){let T=p.shift();bodyContains(T)&&(w=T)}w&&(triggerEvent(w,"htmx:afterRequest",C),triggerEvent(w,"htmx:afterOnLoad",C))}maybeCall(s)}catch(p){throw triggerErrorEvent(n,"htmx:onLoadError",mergeObjects({error:p},C)),p}finally{g()}},E.onerror=function(){removeRequestIndicators(L,O),triggerErrorEvent(n,"htmx:afterRequest",C),triggerErrorEvent(n,"htmx:sendError",C),maybeCall(a),g()},E.onabort=function(){removeRequestIndicators(L,O),triggerErrorEvent(n,"htmx:afterRequest",C),triggerErrorEvent(n,"htmx:sendAbort",C),maybeCall(a),g()},E.ontimeout=function(){removeRequestIndicators(L,O),triggerErrorEvent(n,"htmx:afterRequest",C),triggerErrorEvent(n,"htmx:timeout",C),maybeCall(a),g()},!triggerEvent(n,"htmx:beforeRequest",C))return maybeCall(s),g(),l;var L=addRequestIndicatorClasses(n),O=disableElements(n);forEach(["loadstart","loadend","progress","abort"],function(p){forEach([E,E.upload],function(w){w.addEventListener(p,function(T){triggerEvent(n,"htmx:xhr:"+p,{lengthComputable:T.lengthComputable,loaded:T.loaded,total:T.total})})})}),triggerEvent(n,"htmx:beforeSend",C);let ie=I?null:encodeParamsForBody(E,n,D);return E.send(ie),l}function determineHistoryUpdates(e,t){let n=t.xhr,r=null,o=null;if(hasHeader(n,/HX-Push:/i)?(r=n.getResponseHeader("HX-Push"),o="push"):hasHeader(n,/HX-Push-Url:/i)?(r=n.getResponseHeader("HX-Push-Url"),o="push"):hasHeader(n,/HX-Replace-Url:/i)&&(r=n.getResponseHeader("HX-Replace-Url"),o="replace"),r)return r==="false"?{}:{type:o,path:r};let i=t.pathInfo.finalRequestPath,s=t.pathInfo.responsePath,a=t.etc.push||getClosestAttributeValue(e,"hx-push-url"),l=t.etc.replace||getClosestAttributeValue(e,"hx-replace-url"),c=getInternalData(e).boosted,h=null,u=null;return a?(h="push",u=a):l?(h="replace",u=l):c&&(h="push",u=s||i),u?u==="false"?{}:(u==="true"&&(u=s||i),t.pathInfo.anchor&&u.indexOf("#")===-1&&(u=u+"#"+t.pathInfo.anchor),{type:h,path:u}):{}}function codeMatches(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function resolveResponseHandling(e){for(var t=0;t<htmx.config.responseHandling.length;t++){var n=htmx.config.responseHandling[t];if(codeMatches(n,e.status))return n}return{swap:!1}}function handleTitle(e){if(e){let t=find("title");t?t.textContent=e:window.document.title=e}}function resolveRetarget(e,t){if(t==="this")return e;let n=asElement(querySelectorExt(e,t));if(n==null)throw triggerErrorEvent(e,"htmx:targetError",{target:t}),new Error(`Invalid re-target ${t}`);return n}function handleAjaxResponse(e,t){let n=t.xhr,r=t.target,o=t.etc,i=t.select;if(!triggerEvent(e,"htmx:beforeOnLoad",t))return;if(hasHeader(n,/HX-Trigger:/i)&&handleTriggerHeader(n,"HX-Trigger",e),hasHeader(n,/HX-Location:/i)){let b=n.getResponseHeader("HX-Location");var s={};b.indexOf("{")===0&&(s=parseJSON(b),b=s.path,delete s.path),s.push=s.push||"true",ajaxHelper("get",b,s);return}let a=hasHeader(n,/HX-Refresh:/i)&&n.getResponseHeader("HX-Refresh")==="true";if(hasHeader(n,/HX-Redirect:/i)){t.keepIndicators=!0,htmx.location.href=n.getResponseHeader("HX-Redirect"),a&&htmx.location.reload();return}if(a){t.keepIndicators=!0,htmx.location.reload();return}let l=determineHistoryUpdates(e,t),c=resolveResponseHandling(n),h=c.swap,u=!!c.error,f=htmx.config.ignoreTitle||c.ignoreTitle,v=c.select;c.target&&(t.target=resolveRetarget(e,c.target));var d=o.swapOverride;d==null&&c.swapOverride&&(d=c.swapOverride),hasHeader(n,/HX-Retarget:/i)&&(t.target=resolveRetarget(e,n.getResponseHeader("HX-Retarget"))),hasHeader(n,/HX-Reswap:/i)&&(d=n.getResponseHeader("HX-Reswap"));var y=n.response,m=mergeObjects({shouldSwap:h,serverResponse:y,isError:u,ignoreTitle:f,selectOverride:v,swapOverride:d},t);if(!(c.event&&!triggerEvent(r,c.event,m))&&triggerEvent(r,"htmx:beforeSwap",m)){if(r=m.target,y=m.serverResponse,u=m.isError,f=m.ignoreTitle,v=m.selectOverride,d=m.swapOverride,t.target=r,t.failed=u,t.successful=!u,m.shouldSwap){n.status===286&&cancelPolling(e),withExtensions(e,function(g){y=g.transformResponse(y,n,e)}),l.type&&saveCurrentPageToHistory();var x=getSwapSpecification(e,d);x.hasOwnProperty("ignoreTitle")||(x.ignoreTitle=f),r.classList.add(htmx.config.swappingClass),i&&(v=i),hasHeader(n,/HX-Reselect:/i)&&(v=n.getResponseHeader("HX-Reselect"));let b=o.selectOOB||getClosestAttributeValue(e,"hx-select-oob"),E=getClosestAttributeValue(e,"hx-select");swap(r,y,x,{select:v==="unset"?null:v||E,selectOOB:b,eventInfo:t,anchor:t.pathInfo.anchor,contextElement:e,afterSwapCallback:function(){if(hasHeader(n,/HX-Trigger-After-Swap:/i)){let g=e;bodyContains(e)||(g=getDocument().body),handleTriggerHeader(n,"HX-Trigger-After-Swap",g)}},afterSettleCallback:function(){if(hasHeader(n,/HX-Trigger-After-Settle:/i)){let g=e;bodyContains(e)||(g=getDocument().body),handleTriggerHeader(n,"HX-Trigger-After-Settle",g)}},beforeSwapCallback:function(){l.type&&(triggerEvent(getDocument().body,"htmx:beforeHistoryUpdate",mergeObjects({history:l},t)),l.type==="push"?(pushUrlIntoHistory(l.path),triggerEvent(getDocument().body,"htmx:pushedIntoHistory",{path:l.path})):(replaceUrlInHistory(l.path),triggerEvent(getDocument().body,"htmx:replacedInHistory",{path:l.path})))}})}u&&triggerErrorEvent(e,"htmx:responseError",mergeObjects({error:"Response Status Error Code "+n.status+" from "+t.pathInfo.requestPath},t))}}let extensions={};function extensionBase(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return!0},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return!1},handleSwap:function(e,t,n,r){return!1},encodeParameters:function(e,t,n){return null}}}function defineExtension(e,t){t.init&&t.init(internalAPI),extensions[e]=mergeObjects(extensionBase(),t)}function removeExtension(e){delete extensions[e]}function getExtensions(e,t,n){if(t==null&&(t=[]),e==null)return t;n==null&&(n=[]);let r=getAttributeValue(e,"hx-ext");return r&&forEach(r.split(","),function(o){if(o=o.replace(/ /g,""),o.slice(0,7)=="ignore:"){n.push(o.slice(7));return}if(n.indexOf(o)<0){let i=extensions[o];i&&t.indexOf(i)<0&&t.push(i)}}),getExtensions(asElement(parentElt(e)),t,n)}var isReady=!1;getDocument().addEventListener("DOMContentLoaded",function(){isReady=!0});function ready(e){isReady||getDocument().readyState==="complete"?e():getDocument().addEventListener("DOMContentLoaded",e)}function insertIndicatorStyles(){if(htmx.config.includeIndicatorStyles!==!1){let e=htmx.config.inlineStyleNonce?` nonce="${htmx.config.inlineStyleNonce}"`:"",t=htmx.config.indicatorClass,n=htmx.config.requestClass;getDocument().head.insertAdjacentHTML("beforeend",`<style${e}>.${t}{opacity:0;visibility: hidden} .${n} .${t}, .${n}.${t}{opacity:1;visibility: visible;transition: opacity 200ms ease-in}</style>`)}}function getMetaConfig(){let e=getDocument().querySelector('meta[name="htmx-config"]');return e?parseJSON(e.content):null}function mergeMetaConfig(){let e=getMetaConfig();e&&(htmx.config=mergeObjects(htmx.config,e))}return ready(function(){mergeMetaConfig(),insertIndicatorStyles();let e=getDocument().body;processNode(e);let t=getDocument().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(r){let o=r.detail.elt||r.target,i=getInternalData(o);i&&i.xhr&&i.xhr.abort()});let n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(r){r.state&&r.state.htmx?(restoreHistory(),forEach(t,function(o){triggerEvent(o,"htmx:restored",{document:getDocument(),triggerEvent})})):n&&n(r)},getWindow().setTimeout(function(){triggerEvent(e,"htmx:load",{}),e=null},0)}),htmx})(),F=se;(function(){let e;F.defineExtension("json-enc",{init:function(t){e=t},onEvent:function(t,n){t==="htmx:configRequest"&&(n.detail.headers["Content-Type"]="application/json")},encodeParameters:function(t,n,r){t.overrideMimeType("text/json");let o={};n.forEach(function(s,a){Object.hasOwn(o,a)?(Array.isArray(o[a])||(o[a]=[o[a]]),o[a].push(s)):o[a]=s});let i=e.getExpressionVars(r);return Object.keys(o).forEach(function(s){o[s]=Object.hasOwn(i,s)?i[s]:o[s]}),JSON.stringify(o)}})})();var K=document.createElement("template");K.innerHTML=`
1
1
+
var se=(function(){"use strict";let htmx={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){return getInputValues(e,t||"post").values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:!0,historyCacheSize:10,refreshOnHistoryMiss:!1,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:!0,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:!0,allowScriptTags:!0,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:!1,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:!1,getCacheBusterParam:!1,globalViewTransitions:!1,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:!0,ignoreTitle:!1,scrollIntoViewOnBoost:!0,triggerSpecsCache:null,disableInheritance:!1,responseHandling:[{code:"204",swap:!1},{code:"[23]..",swap:!0},{code:"[45]..",swap:!1,error:!0}],allowNestedOobSwaps:!0,historyRestoreAsHxRequest:!0,reportValidityOfForms:!1},parseInterval:null,location,_:null,version:"2.0.8"};htmx.onLoad=onLoadHelper,htmx.process=processNode,htmx.on=addEventListenerImpl,htmx.off=removeEventListenerImpl,htmx.trigger=triggerEvent,htmx.ajax=ajaxHelper,htmx.find=find,htmx.findAll=findAll,htmx.closest=closest,htmx.remove=removeElement,htmx.addClass=addClassToElement,htmx.removeClass=removeClassFromElement,htmx.toggleClass=toggleClassOnElement,htmx.takeClass=takeClassForElement,htmx.swap=swap,htmx.defineExtension=defineExtension,htmx.removeExtension=removeExtension,htmx.logAll=logAll,htmx.logNone=logNone,htmx.parseInterval=parseInterval,htmx._=internalEval;let internalAPI={addTriggerHandler,bodyContains,canAccessLocalStorage,findThisElement,filterValues,swap,hasAttribute,getAttributeValue,getClosestAttributeValue,getClosestMatch,getExpressionVars,getHeaders,getInputValues,getInternalData,getSwapSpecification,getTriggerSpecs,getTarget,makeFragment,mergeObjects,makeSettleInfo,oobSwap,querySelectorExt,settleImmediately,shouldCancel,triggerEvent,triggerErrorEvent,withExtensions},VERBS=["get","post","put","delete","patch"],VERB_SELECTOR=VERBS.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");function parseInterval(e){if(e==null)return;let t=NaN;return e.slice(-2)=="ms"?t=parseFloat(e.slice(0,-2)):e.slice(-1)=="s"?t=parseFloat(e.slice(0,-1))*1e3:e.slice(-1)=="m"?t=parseFloat(e.slice(0,-1))*1e3*60:t=parseFloat(e),isNaN(t)?void 0:t}function getRawAttribute(e,t){return e instanceof Element&&e.getAttribute(t)}function hasAttribute(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function getAttributeValue(e,t){return getRawAttribute(e,t)||getRawAttribute(e,"data-"+t)}function parentElt(e){let t=e.parentElement;return!t&&e.parentNode instanceof ShadowRoot?e.parentNode:t}function getDocument(){return document}function getRootNode(e,t){return e.getRootNode?e.getRootNode({composed:t}):getDocument()}function getClosestMatch(e,t){for(;e&&!t(e);)e=parentElt(e);return e||null}function getAttributeValueWithDisinheritance(e,t,n){let r=getAttributeValue(t,n),o=getAttributeValue(t,"hx-disinherit");var i=getAttributeValue(t,"hx-inherit");if(e!==t){if(htmx.config.disableInheritance)return i&&(i==="*"||i.split(" ").indexOf(n)>=0)?r:null;if(o&&(o==="*"||o.split(" ").indexOf(n)>=0))return"unset"}return r}function getClosestAttributeValue(e,t){let n=null;if(getClosestMatch(e,function(r){return!!(n=getAttributeValueWithDisinheritance(e,asElement(r),t))}),n!=="unset")return n}function matches(e,t){return e instanceof Element&&e.matches(t)}function getStartTag(e){let n=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i.exec(e);return n?n[1].toLowerCase():""}function parseHTML(e){return"parseHTMLUnsafe"in Document?Document.parseHTMLUnsafe(e):new DOMParser().parseFromString(e,"text/html")}function takeChildrenFor(e,t){for(;t.childNodes.length>0;)e.append(t.childNodes[0])}function duplicateScript(e){let t=getDocument().createElement("script");return forEach(e.attributes,function(n){t.setAttribute(n.name,n.value)}),t.textContent=e.textContent,t.async=!1,htmx.config.inlineScriptNonce&&(t.nonce=htmx.config.inlineScriptNonce),t}function isJavaScriptScriptNode(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function normalizeScriptTags(e){Array.from(e.querySelectorAll("script")).forEach(t=>{if(isJavaScriptScriptNode(t)){let n=duplicateScript(t),r=t.parentNode;try{r.insertBefore(n,t)}catch(o){logError(o)}finally{t.remove()}}})}function makeFragment(e){let t=e.replace(/<head(\s[^>]*)?>[\s\S]*?<\/head>/i,""),n=getStartTag(t),r;if(n==="html"){r=new DocumentFragment;let i=parseHTML(e);takeChildrenFor(r,i.body),r.title=i.title}else if(n==="body"){r=new DocumentFragment;let i=parseHTML(t);takeChildrenFor(r,i.body),r.title=i.title}else{let i=parseHTML('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content,r.title=i.title;var o=r.querySelector("title");o&&o.parentNode===r&&(o.remove(),r.title=o.innerText)}return r&&(htmx.config.allowScriptTags?normalizeScriptTags(r):r.querySelectorAll("script").forEach(i=>i.remove())),r}function maybeCall(e){e&&e()}function isType(e,t){return Object.prototype.toString.call(e)==="[object "+t+"]"}function isFunction(e){return typeof e=="function"}function isRawObject(e){return isType(e,"Object")}function getInternalData(e){let t="htmx-internal-data",n=e[t];return n||(n=e[t]={}),n}function toArray(e){let t=[];if(e)for(let n=0;n<e.length;n++)t.push(e[n]);return t}function forEach(e,t){if(e)for(let n=0;n<e.length;n++)t(e[n])}function isScrolledIntoView(e){let t=e.getBoundingClientRect(),n=t.top,r=t.bottom;return n<window.innerHeight&&r>=0}function bodyContains(e){return e.getRootNode({composed:!0})===document}function splitOnWhitespace(e){return e.trim().split(/\s+/)}function mergeObjects(e,t){for(let n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function parseJSON(e){try{return JSON.parse(e)}catch(t){return logError(t),null}}function canAccessLocalStorage(){let e="htmx:sessionStorageTest";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch{return!1}}function normalizePath(e){let t=new URL(e,"http://x");return t&&(e=t.pathname+t.search),e!="/"&&(e=e.replace(/\/+$/,"")),e}function internalEval(str){return maybeEval(getDocument().body,function(){return eval(str)})}function onLoadHelper(e){return htmx.on("htmx:load",function(n){e(n.detail.elt)})}function logAll(){htmx.logger=function(e,t,n){console&&console.log(t,e,n)}}function logNone(){htmx.logger=null}function find(e,t){return typeof e!="string"?e.querySelector(t):find(getDocument(),e)}function findAll(e,t){return typeof e!="string"?e.querySelectorAll(t):findAll(getDocument(),e)}function getWindow(){return window}function removeElement(e,t){e=resolveTarget(e),t?getWindow().setTimeout(function(){removeElement(e),e=null},t):parentElt(e).removeChild(e)}function asElement(e){return e instanceof Element?e:null}function asHtmlElement(e){return e instanceof HTMLElement?e:null}function asString(e){return typeof e=="string"?e:null}function asParentNode(e){return e instanceof Element||e instanceof Document||e instanceof DocumentFragment?e:null}function addClassToElement(e,t,n){e=asElement(resolveTarget(e)),e&&(n?getWindow().setTimeout(function(){addClassToElement(e,t),e=null},n):e.classList&&e.classList.add(t))}function removeClassFromElement(e,t,n){let r=asElement(resolveTarget(e));r&&(n?getWindow().setTimeout(function(){removeClassFromElement(r,t),r=null},n):r.classList&&(r.classList.remove(t),r.classList.length===0&&r.removeAttribute("class")))}function toggleClassOnElement(e,t){e=resolveTarget(e),e.classList.toggle(t)}function takeClassForElement(e,t){e=resolveTarget(e),forEach(e.parentElement.children,function(n){removeClassFromElement(n,t)}),addClassToElement(asElement(e),t)}function closest(e,t){return e=asElement(resolveTarget(e)),e?e.closest(t):null}function startsWith(e,t){return e.substring(0,t.length)===t}function endsWith(e,t){return e.substring(e.length-t.length)===t}function normalizeSelector(e){let t=e.trim();return startsWith(t,"<")&&endsWith(t,"/>")?t.substring(1,t.length-2):t}function querySelectorAllExt(e,t,n){if(t.indexOf("global ")===0)return querySelectorAllExt(e,t.slice(7),!0);e=resolveTarget(e);let r=[];{let s=0,a=0;for(let l=0;l<t.length;l++){let c=t[l];if(c===","&&s===0){r.push(t.substring(a,l)),a=l+1;continue}c==="<"?s++:c==="/"&&l<t.length-1&&t[l+1]===">"&&s--}a<t.length&&r.push(t.substring(a))}let o=[],i=[];for(;r.length>0;){let s=normalizeSelector(r.shift()),a;s.indexOf("closest ")===0?a=closest(asElement(e),normalizeSelector(s.slice(8))):s.indexOf("find ")===0?a=find(asParentNode(e),normalizeSelector(s.slice(5))):s==="next"||s==="nextElementSibling"?a=asElement(e).nextElementSibling:s.indexOf("next ")===0?a=scanForwardQuery(e,normalizeSelector(s.slice(5)),!!n):s==="previous"||s==="previousElementSibling"?a=asElement(e).previousElementSibling:s.indexOf("previous ")===0?a=scanBackwardsQuery(e,normalizeSelector(s.slice(9)),!!n):s==="document"?a=document:s==="window"?a=window:s==="body"?a=document.body:s==="root"?a=getRootNode(e,!!n):s==="host"?a=e.getRootNode().host:i.push(s),a&&o.push(a)}if(i.length>0){let s=i.join(","),a=asParentNode(getRootNode(e,!!n));o.push(...toArray(a.querySelectorAll(s)))}return o}var scanForwardQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=0;o<r.length;o++){let i=r[o];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_PRECEDING)return i}},scanBackwardsQuery=function(e,t,n){let r=asParentNode(getRootNode(e,n)).querySelectorAll(t);for(let o=r.length-1;o>=0;o--){let i=r[o];if(i.compareDocumentPosition(e)===Node.DOCUMENT_POSITION_FOLLOWING)return i}};function querySelectorExt(e,t){return typeof e!="string"?querySelectorAllExt(e,t)[0]:querySelectorAllExt(getDocument().body,e)[0]}function resolveTarget(e,t){return typeof e=="string"?find(asParentNode(t)||document,e):e}function processEventArgs(e,t,n,r){return isFunction(t)?{target:getDocument().body,event:asString(e),listener:t,options:n}:{target:resolveTarget(e),event:asString(t),listener:n,options:r}}function addEventListenerImpl(e,t,n,r){return ready(function(){let i=processEventArgs(e,t,n,r);i.target.addEventListener(i.event,i.listener,i.options)}),isFunction(t)?t:n}function removeEventListenerImpl(e,t,n){return ready(function(){let r=processEventArgs(e,t,n);r.target.removeEventListener(r.event,r.listener)}),isFunction(t)?t:n}let DUMMY_ELT=getDocument().createElement("output");function findAttributeTargets(e,t){let n=getClosestAttributeValue(e,t);if(n){if(n==="this")return[findThisElement(e,t)];{let r=querySelectorAllExt(e,n);if(/(^|,)(\s*)inherit(\s*)($|,)/.test(n)){let i=asElement(getClosestMatch(e,function(s){return s!==e&&hasAttribute(asElement(s),t)}));i&&r.push(...findAttributeTargets(i,t))}return r.length===0?(logError('The selector "'+n+'" on '+t+" returned no matches!"),[DUMMY_ELT]):r}}}function findThisElement(e,t){return asElement(getClosestMatch(e,function(n){return getAttributeValue(asElement(n),t)!=null}))}function getTarget(e){let t=getClosestAttributeValue(e,"hx-target");return t?t==="this"?findThisElement(e,"hx-target"):querySelectorExt(e,t):getInternalData(e).boosted?getDocument().body:e}function shouldSettleAttribute(e){return htmx.config.attributesToSettle.includes(e)}function cloneAttributes(e,t){forEach(Array.from(e.attributes),function(n){!t.hasAttribute(n.name)&&shouldSettleAttribute(n.name)&&e.removeAttribute(n.name)}),forEach(t.attributes,function(n){shouldSettleAttribute(n.name)&&e.setAttribute(n.name,n.value)})}function isInlineSwap(e,t){let n=getExtensions(t);for(let r=0;r<n.length;r++){let o=n[r];try{if(o.isInlineSwap(e))return!0}catch(i){logError(i)}}return e==="outerHTML"}function oobSwap(e,t,n,r){r=r||getDocument();let o="#"+CSS.escape(getRawAttribute(t,"id")),i="outerHTML";e==="true"||(e.indexOf(":")>0?(i=e.substring(0,e.indexOf(":")),o=e.substring(e.indexOf(":")+1)):i=e),t.removeAttribute("hx-swap-oob"),t.removeAttribute("data-hx-swap-oob");let s=querySelectorAllExt(r,o,!1);return s.length?(forEach(s,function(a){let l,c=t.cloneNode(!0);l=getDocument().createDocumentFragment(),l.appendChild(c),isInlineSwap(i,a)||(l=asParentNode(c));let h={shouldSwap:!0,target:a,fragment:l};triggerEvent(a,"htmx:oobBeforeSwap",h)&&(a=h.target,h.shouldSwap&&(handlePreservedElements(l),swapWithStyle(i,a,a,l,n),restorePreservedElements()),forEach(n.elts,function(u){triggerEvent(u,"htmx:oobAfterSwap",h)}))}),t.parentNode.removeChild(t)):(t.parentNode.removeChild(t),triggerErrorEvent(getDocument().body,"htmx:oobErrorNoTarget",{content:t})),e}function restorePreservedElements(){let e=find("#--htmx-preserve-pantry--");if(e){for(let t of[...e.children]){let n=find("#"+t.id);n.parentNode.moveBefore(t,n),n.remove()}e.remove()}}function handlePreservedElements(e){forEach(findAll(e,"[hx-preserve], [data-hx-preserve]"),function(t){let n=getAttributeValue(t,"id"),r=getDocument().getElementById(n);if(r!=null)if(t.moveBefore){let o=find("#--htmx-preserve-pantry--");o==null&&(getDocument().body.insertAdjacentHTML("afterend","<div id='--htmx-preserve-pantry--'></div>"),o=find("#--htmx-preserve-pantry--")),o.moveBefore(r,null)}else t.parentNode.replaceChild(r,t)})}function handleAttributes(e,t,n){forEach(t.querySelectorAll("[id]"),function(r){let o=getRawAttribute(r,"id");if(o&&o.length>0){let i=o.replace("'","\\'"),s=r.tagName.replace(":","\\:"),a=asParentNode(e),l=a&&a.querySelector(s+"[id='"+i+"']");if(l&&l!==a){let c=r.cloneNode();cloneAttributes(r,l),n.tasks.push(function(){cloneAttributes(r,c)})}}})}function makeAjaxLoadTask(e){return function(){removeClassFromElement(e,htmx.config.addedClass),processNode(asElement(e)),processFocus(asParentNode(e)),triggerEvent(e,"htmx:load")}}function processFocus(e){let t="[autofocus]",n=asHtmlElement(matches(e,t)?e:e.querySelector(t));n?.focus()}function insertNodesBefore(e,t,n,r){for(handleAttributes(e,n,r);n.childNodes.length>0;){let o=n.firstChild;addClassToElement(asElement(o),htmx.config.addedClass),e.insertBefore(o,t),o.nodeType!==Node.TEXT_NODE&&o.nodeType!==Node.COMMENT_NODE&&r.tasks.push(makeAjaxLoadTask(o))}}function stringHash(e,t){let n=0;for(;n<e.length;)t=(t<<5)-t+e.charCodeAt(n++)|0;return t}function attributeHash(e){let t=0;for(let n=0;n<e.attributes.length;n++){let r=e.attributes[n];r.value&&(t=stringHash(r.name,t),t=stringHash(r.value,t))}return t}function deInitOnHandlers(e){let t=getInternalData(e);if(t.onHandlers){for(let n=0;n<t.onHandlers.length;n++){let r=t.onHandlers[n];removeEventListenerImpl(e,r.event,r.listener)}delete t.onHandlers}}function deInitNode(e){let t=getInternalData(e);t.timeout&&clearTimeout(t.timeout),t.listenerInfos&&forEach(t.listenerInfos,function(n){n.on&&removeEventListenerImpl(n.on,n.trigger,n.listener)}),deInitOnHandlers(e),forEach(Object.keys(t),function(n){n!=="firstInitCompleted"&&delete t[n]})}function cleanUpElement(e){triggerEvent(e,"htmx:beforeCleanupElement"),deInitNode(e),forEach(e.children,function(t){cleanUpElement(t)})}function swapOuterHTML(e,t,n){if(e.tagName==="BODY")return swapInnerHTML(e,t,n);let r,o=e.previousSibling,i=parentElt(e);if(i){for(insertNodesBefore(i,e,t,n),o==null?r=i.firstChild:r=o.nextSibling,n.elts=n.elts.filter(function(s){return s!==e});r&&r!==e;)r instanceof Element&&n.elts.push(r),r=r.nextSibling;cleanUpElement(e),e.remove()}}function swapAfterBegin(e,t,n){return insertNodesBefore(e,e.firstChild,t,n)}function swapBeforeBegin(e,t,n){return insertNodesBefore(parentElt(e),e,t,n)}function swapBeforeEnd(e,t,n){return insertNodesBefore(e,null,t,n)}function swapAfterEnd(e,t,n){return insertNodesBefore(parentElt(e),e.nextSibling,t,n)}function swapDelete(e){cleanUpElement(e);let t=parentElt(e);if(t)return t.removeChild(e)}function swapInnerHTML(e,t,n){let r=e.firstChild;if(insertNodesBefore(e,r,t,n),r){for(;r.nextSibling;)cleanUpElement(r.nextSibling),e.removeChild(r.nextSibling);cleanUpElement(r),e.removeChild(r)}}function swapWithStyle(e,t,n,r,o){switch(e){case"none":return;case"outerHTML":swapOuterHTML(n,r,o);return;case"afterbegin":swapAfterBegin(n,r,o);return;case"beforebegin":swapBeforeBegin(n,r,o);return;case"beforeend":swapBeforeEnd(n,r,o);return;case"afterend":swapAfterEnd(n,r,o);return;case"delete":swapDelete(n);return;default:var i=getExtensions(t);for(let s=0;s<i.length;s++){let a=i[s];try{let l=a.handleSwap(e,n,r,o);if(l){if(Array.isArray(l))for(let c=0;c<l.length;c++){let h=l[c];h.nodeType!==Node.TEXT_NODE&&h.nodeType!==Node.COMMENT_NODE&&o.tasks.push(makeAjaxLoadTask(h))}return}}catch(l){logError(l)}}e==="innerHTML"?swapInnerHTML(n,r,o):swapWithStyle(htmx.config.defaultSwapStyle,t,n,r,o)}}function findAndSwapOobElements(e,t,n){var r=findAll(e,"[hx-swap-oob], [data-hx-swap-oob]");return forEach(r,function(o){if(htmx.config.allowNestedOobSwaps||o.parentElement===null){let i=getAttributeValue(o,"hx-swap-oob");i!=null&&oobSwap(i,o,t,n)}else o.removeAttribute("hx-swap-oob"),o.removeAttribute("data-hx-swap-oob")}),r.length>0}function swap(e,t,n,r){r||(r={});let o=null,i=null,s=function(){maybeCall(r.beforeSwapCallback),e=resolveTarget(e);let c=r.contextElement?getRootNode(r.contextElement,!1):getDocument(),h=document.activeElement,u={};u={elt:h,start:h?h.selectionStart:null,end:h?h.selectionEnd:null};let f=makeSettleInfo(e);if(n.swapStyle==="textContent")e.textContent=t;else{let d=makeFragment(t);if(f.title=r.title||d.title,r.historyRequest&&(d=d.querySelector("[hx-history-elt],[data-hx-history-elt]")||d),r.selectOOB){let y=r.selectOOB.split(",");for(let m=0;m<y.length;m++){let x=y[m].split(":",2),b=x[0].trim();b.indexOf("#")===0&&(b=b.substring(1));let E=x[1]||"true",g=d.querySelector("#"+b);g&&oobSwap(E,g,f,c)}}if(findAndSwapOobElements(d,f,c),forEach(findAll(d,"template"),function(y){y.content&&findAndSwapOobElements(y.content,f,c)&&y.remove()}),r.select){let y=getDocument().createDocumentFragment();forEach(d.querySelectorAll(r.select),function(m){y.appendChild(m)}),d=y}handlePreservedElements(d),swapWithStyle(n.swapStyle,r.contextElement,e,d,f),restorePreservedElements()}if(u.elt&&!bodyContains(u.elt)&&getRawAttribute(u.elt,"id")){let d=document.getElementById(getRawAttribute(u.elt,"id")),y={preventScroll:n.focusScroll!==void 0?!n.focusScroll:!htmx.config.defaultFocusScroll};if(d){if(u.start&&d.setSelectionRange)try{d.setSelectionRange(u.start,u.end)}catch{}d.focus(y)}}e.classList.remove(htmx.config.swappingClass),forEach(f.elts,function(d){d.classList&&d.classList.add(htmx.config.settlingClass),triggerEvent(d,"htmx:afterSwap",r.eventInfo)}),maybeCall(r.afterSwapCallback),n.ignoreTitle||handleTitle(f.title);let v=function(){if(forEach(f.tasks,function(d){d.call()}),forEach(f.elts,function(d){d.classList&&d.classList.remove(htmx.config.settlingClass),triggerEvent(d,"htmx:afterSettle",r.eventInfo)}),r.anchor){let d=asElement(resolveTarget("#"+r.anchor));d&&d.scrollIntoView({block:"start",behavior:"auto"})}updateScrollState(f.elts,n),maybeCall(r.afterSettleCallback),maybeCall(o)};n.settleDelay>0?getWindow().setTimeout(v,n.settleDelay):v()},a=htmx.config.globalViewTransitions;n.hasOwnProperty("transition")&&(a=n.transition);let l=r.contextElement||getDocument();if(a&&triggerEvent(l,"htmx:beforeTransition",r.eventInfo)&&typeof Promise<"u"&&document.startViewTransition){let c=new Promise(function(u,f){o=u,i=f}),h=s;s=function(){document.startViewTransition(function(){return h(),c})}}try{n?.swapDelay&&n.swapDelay>0?getWindow().setTimeout(s,n.swapDelay):s()}catch(c){throw triggerErrorEvent(l,"htmx:swapError",r.eventInfo),maybeCall(i),c}}function handleTriggerHeader(e,t,n){let r=e.getResponseHeader(t);if(r.indexOf("{")===0){let o=parseJSON(r);for(let i in o)if(o.hasOwnProperty(i)){let s=o[i];isRawObject(s)?n=s.target!==void 0?s.target:n:s={value:s},triggerEvent(n,i,s)}}else{let o=r.split(",");for(let i=0;i<o.length;i++)triggerEvent(n,o[i].trim(),[])}}let WHITESPACE=/\s/,WHITESPACE_OR_COMMA=/[\s,]/,SYMBOL_START=/[_$a-zA-Z]/,SYMBOL_CONT=/[_$a-zA-Z0-9]/,STRINGISH_START=['"',"'","/"],NOT_WHITESPACE=/[^\s]/,COMBINED_SELECTOR_START=/[{(]/,COMBINED_SELECTOR_END=/[})]/;function tokenizeString(e){let t=[],n=0;for(;n<e.length;){if(SYMBOL_START.exec(e.charAt(n))){for(var r=n;SYMBOL_CONT.exec(e.charAt(n+1));)n++;t.push(e.substring(r,n+1))}else if(STRINGISH_START.indexOf(e.charAt(n))!==-1){let o=e.charAt(n);var r=n;for(n++;n<e.length&&e.charAt(n)!==o;)e.charAt(n)==="\\"&&n++,n++;t.push(e.substring(r,n+1))}else{let o=e.charAt(n);t.push(o)}n++}return t}function isPossibleRelativeReference(e,t,n){return SYMBOL_START.exec(e.charAt(0))&&e!=="true"&&e!=="false"&&e!=="this"&&e!==n&&t!=="."}function maybeGenerateConditional(e,t,n){if(t[0]==="["){t.shift();let r=1,o=" return (function("+n+"){ return (",i=null;for(;t.length>0;){let s=t[0];if(s==="]"){if(r--,r===0){i===null&&(o=o+"true"),t.shift(),o+=")})";try{let a=maybeEval(e,function(){return Function(o)()},function(){return!0});return a.source=o,a}catch(a){return triggerErrorEvent(getDocument().body,"htmx:syntax:error",{error:a,source:o}),null}}}else s==="["&&r++;isPossibleRelativeReference(s,i,n)?o+="(("+n+"."+s+") ? ("+n+"."+s+") : (window."+s+"))":o=o+s,i=t.shift()}}}function consumeUntil(e,t){let n="";for(;e.length>0&&!t.test(e[0]);)n+=e.shift();return n}function consumeCSSSelector(e){let t;return e.length>0&&COMBINED_SELECTOR_START.test(e[0])?(e.shift(),t=consumeUntil(e,COMBINED_SELECTOR_END).trim(),e.shift()):t=consumeUntil(e,WHITESPACE_OR_COMMA),t}let INPUT_SELECTOR="input, textarea, select";function parseAndCacheTrigger(e,t,n){let r=[],o=tokenizeString(t);do{consumeUntil(o,NOT_WHITESPACE);let a=o.length,l=consumeUntil(o,/[,\[\s]/);if(l!=="")if(l==="every"){let c={trigger:"every"};consumeUntil(o,NOT_WHITESPACE),c.pollInterval=parseInterval(consumeUntil(o,/[,\[\s]/)),consumeUntil(o,NOT_WHITESPACE);var i=maybeGenerateConditional(e,o,"event");i&&(c.eventFilter=i),r.push(c)}else{let c={trigger:l};var i=maybeGenerateConditional(e,o,"event");for(i&&(c.eventFilter=i),consumeUntil(o,NOT_WHITESPACE);o.length>0&&o[0]!==",";){let u=o.shift();if(u==="changed")c.changed=!0;else if(u==="once")c.once=!0;else if(u==="consume")c.consume=!0;else if(u==="delay"&&o[0]===":")o.shift(),c.delay=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA));else if(u==="from"&&o[0]===":"){if(o.shift(),COMBINED_SELECTOR_START.test(o[0]))var s=consumeCSSSelector(o);else{var s=consumeUntil(o,WHITESPACE_OR_COMMA);if(s==="closest"||s==="find"||s==="next"||s==="previous"){o.shift();let v=consumeCSSSelector(o);v.length>0&&(s+=" "+v)}}c.from=s}else u==="target"&&o[0]===":"?(o.shift(),c.target=consumeCSSSelector(o)):u==="throttle"&&o[0]===":"?(o.shift(),c.throttle=parseInterval(consumeUntil(o,WHITESPACE_OR_COMMA))):u==="queue"&&o[0]===":"?(o.shift(),c.queue=consumeUntil(o,WHITESPACE_OR_COMMA)):u==="root"&&o[0]===":"?(o.shift(),c[u]=consumeCSSSelector(o)):u==="threshold"&&o[0]===":"?(o.shift(),c[u]=consumeUntil(o,WHITESPACE_OR_COMMA)):triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()});consumeUntil(o,NOT_WHITESPACE)}r.push(c)}o.length===a&&triggerErrorEvent(e,"htmx:syntax:error",{token:o.shift()}),consumeUntil(o,NOT_WHITESPACE)}while(o[0]===","&&o.shift());return n&&(n[t]=r),r}function getTriggerSpecs(e){let t=getAttributeValue(e,"hx-trigger"),n=[];if(t){let r=htmx.config.triggerSpecsCache;n=r&&r[t]||parseAndCacheTrigger(e,t,r)}return n.length>0?n:matches(e,"form")?[{trigger:"submit"}]:matches(e,'input[type="button"], input[type="submit"]')?[{trigger:"click"}]:matches(e,INPUT_SELECTOR)?[{trigger:"change"}]:[{trigger:"click"}]}function cancelPolling(e){getInternalData(e).cancelled=!0}function processPolling(e,t,n){let r=getInternalData(e);r.timeout=getWindow().setTimeout(function(){bodyContains(e)&&r.cancelled!==!0&&(maybeFilterEvent(n,e,makeEvent("hx:poll:trigger",{triggerSpec:n,target:e}))||t(e),processPolling(e,t,n))},n.pollInterval)}function isLocalLink(e){return location.hostname===e.hostname&&getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")!==0}function eltIsDisabled(e){return closest(e,htmx.config.disableSelector)}function boostElement(e,t,n){if(e instanceof HTMLAnchorElement&&isLocalLink(e)&&(e.target===""||e.target==="_self")||e.tagName==="FORM"&&String(getRawAttribute(e,"method")).toLowerCase()!=="dialog"){t.boosted=!0;let r,o;if(e.tagName==="A")r="get",o=getRawAttribute(e,"href");else{let i=getRawAttribute(e,"method");r=i?i.toLowerCase():"get",o=getRawAttribute(e,"action"),(o==null||o==="")&&(o=location.href),r==="get"&&o.includes("?")&&(o=o.replace(/\?[^#]+/,""))}n.forEach(function(i){addEventListener(e,function(s,a){let l=asElement(s);if(eltIsDisabled(l)){cleanUpElement(l);return}issueAjaxRequest(r,o,l,a)},t,i,!0)})}}function shouldCancel(e,t){if(e.type==="submit"&&t.tagName==="FORM")return!0;if(e.type==="click"){let n=t.closest('input[type="submit"], button');if(n&&n.form&&n.type==="submit")return!0;let r=t.closest("a"),o=/^#.+/;if(r&&r.href&&!o.test(r.getAttribute("href")))return!0}return!1}function ignoreBoostedAnchorCtrlClick(e,t){return getInternalData(e).boosted&&e instanceof HTMLAnchorElement&&t.type==="click"&&(t.ctrlKey||t.metaKey)}function maybeFilterEvent(e,t,n){let r=e.eventFilter;if(r)try{return r.call(t,n)!==!0}catch(o){let i=r.source;return triggerErrorEvent(getDocument().body,"htmx:eventFilter:error",{error:o,source:i}),!0}return!1}function addEventListener(e,t,n,r,o){let i=getInternalData(e),s;r.from?s=querySelectorAllExt(e,r.from):s=[e],r.changed&&("lastValue"in i||(i.lastValue=new WeakMap),s.forEach(function(a){i.lastValue.has(r)||i.lastValue.set(r,new WeakMap),i.lastValue.get(r).set(a,a.value)})),forEach(s,function(a){let l=function(c){if(!bodyContains(e)){a.removeEventListener(r.trigger,l);return}if(ignoreBoostedAnchorCtrlClick(e,c)||((o||shouldCancel(c,a))&&c.preventDefault(),maybeFilterEvent(r,e,c)))return;let h=getInternalData(c);if(h.triggerSpec=r,h.handledFor==null&&(h.handledFor=[]),h.handledFor.indexOf(e)<0){if(h.handledFor.push(e),r.consume&&c.stopPropagation(),r.target&&c.target&&!matches(asElement(c.target),r.target))return;if(r.once){if(i.triggeredOnce)return;i.triggeredOnce=!0}if(r.changed){let u=c.target,f=u.value,v=i.lastValue.get(r);if(v.has(u)&&v.get(u)===f)return;v.set(u,f)}if(i.delayed&&clearTimeout(i.delayed),i.throttle)return;r.throttle>0?i.throttle||(triggerEvent(e,"htmx:trigger"),t(e,c),i.throttle=getWindow().setTimeout(function(){i.throttle=null},r.throttle)):r.delay>0?i.delayed=getWindow().setTimeout(function(){triggerEvent(e,"htmx:trigger"),t(e,c)},r.delay):(triggerEvent(e,"htmx:trigger"),t(e,c))}};n.listenerInfos==null&&(n.listenerInfos=[]),n.listenerInfos.push({trigger:r.trigger,listener:l,on:a}),a.addEventListener(r.trigger,l)})}let windowIsScrolling=!1,scrollHandler=null;function initScrollHandler(){scrollHandler||(scrollHandler=function(){windowIsScrolling=!0},window.addEventListener("scroll",scrollHandler),window.addEventListener("resize",scrollHandler),setInterval(function(){windowIsScrolling&&(windowIsScrolling=!1,forEach(getDocument().querySelectorAll("[hx-trigger*='revealed'],[data-hx-trigger*='revealed']"),function(e){maybeReveal(e)}))},200))}function maybeReveal(e){!hasAttribute(e,"data-hx-revealed")&&isScrolledIntoView(e)&&(e.setAttribute("data-hx-revealed","true"),getInternalData(e).initHash?triggerEvent(e,"revealed"):e.addEventListener("htmx:afterProcessNode",function(){triggerEvent(e,"revealed")},{once:!0}))}function loadImmediately(e,t,n,r){let o=function(){n.loaded||(n.loaded=!0,triggerEvent(e,"htmx:trigger"),t(e))};r>0?getWindow().setTimeout(o,r):o()}function processVerbs(e,t,n){let r=!1;return forEach(VERBS,function(o){if(hasAttribute(e,"hx-"+o)){let i=getAttributeValue(e,"hx-"+o);r=!0,t.path=i,t.verb=o,n.forEach(function(s){addTriggerHandler(e,s,t,function(a,l){let c=asElement(a);if(eltIsDisabled(c)){cleanUpElement(c);return}issueAjaxRequest(o,i,c,l)})})}}),r}function addTriggerHandler(e,t,n,r){if(t.trigger==="revealed")initScrollHandler(),addEventListener(e,r,n,t),maybeReveal(asElement(e));else if(t.trigger==="intersect"){let o={};t.root&&(o.root=querySelectorExt(e,t.root)),t.threshold&&(o.threshold=parseFloat(t.threshold)),new IntersectionObserver(function(s){for(let a=0;a<s.length;a++)if(s[a].isIntersecting){triggerEvent(e,"intersect");break}},o).observe(asElement(e)),addEventListener(asElement(e),r,n,t)}else!n.firstInitCompleted&&t.trigger==="load"?maybeFilterEvent(t,e,makeEvent("load",{elt:e}))||loadImmediately(asElement(e),r,n,t.delay):t.pollInterval>0?(n.polling=!0,processPolling(asElement(e),r,t)):addEventListener(e,r,n,t)}function shouldProcessHxOn(e){let t=asElement(e);if(!t)return!1;let n=t.attributes;for(let r=0;r<n.length;r++){let o=n[r].name;if(startsWith(o,"hx-on:")||startsWith(o,"data-hx-on:")||startsWith(o,"hx-on-")||startsWith(o,"data-hx-on-"))return!0}return!1}let HX_ON_QUERY=new XPathEvaluator().createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');function processHXOnRoot(e,t){shouldProcessHxOn(e)&&t.push(asElement(e));let n=HX_ON_QUERY.evaluate(e),r=null;for(;r=n.iterateNext();)t.push(asElement(r))}function findHxOnWildcardElements(e){let t=[];if(e instanceof DocumentFragment)for(let n of e.childNodes)processHXOnRoot(n,t);else processHXOnRoot(e,t);return t}function findElementsToProcess(e){if(e.querySelectorAll){let n=", [hx-boost] a, [data-hx-boost] a, a[hx-boost], a[data-hx-boost]",r=[];for(let i in extensions){let s=extensions[i];if(s.getSelectors){var t=s.getSelectors();t&&r.push(t)}}return e.querySelectorAll(VERB_SELECTOR+n+", form, [type='submit'], [hx-ext], [data-hx-ext], [hx-trigger], [data-hx-trigger]"+r.flat().map(i=>", "+i).join(""))}else return[]}function maybeSetLastButtonClicked(e){let t=getTargetButton(e.target),n=getRelatedFormData(e);n&&(n.lastButtonClicked=t)}function maybeUnsetLastButtonClicked(e){let t=getRelatedFormData(e);t&&(t.lastButtonClicked=null)}function getTargetButton(e){return closest(asElement(e),"button, input[type='submit']")}function getRelatedForm(e){return e.form||closest(e,"form")}function getRelatedFormData(e){let t=getTargetButton(e.target);if(!t)return;let n=getRelatedForm(t);if(n)return getInternalData(n)}function initButtonTracking(e){e.addEventListener("click",maybeSetLastButtonClicked),e.addEventListener("focusin",maybeSetLastButtonClicked),e.addEventListener("focusout",maybeUnsetLastButtonClicked)}function addHxOnEventHandler(e,t,n){let r=getInternalData(e);Array.isArray(r.onHandlers)||(r.onHandlers=[]);let o,i=function(s){maybeEval(e,function(){eltIsDisabled(e)||(o||(o=new Function("event",n)),o.call(e,s))})};e.addEventListener(t,i),r.onHandlers.push({event:t,listener:i})}function processHxOnWildcard(e){deInitOnHandlers(e);for(let t=0;t<e.attributes.length;t++){let n=e.attributes[t].name,r=e.attributes[t].value;if(startsWith(n,"hx-on")||startsWith(n,"data-hx-on")){let o=n.indexOf("-on")+3,i=n.slice(o,o+1);if(i==="-"||i===":"){let s=n.slice(o+1);startsWith(s,":")?s="htmx"+s:startsWith(s,"-")?s="htmx:"+s.slice(1):startsWith(s,"htmx-")&&(s="htmx:"+s.slice(5)),addHxOnEventHandler(e,s,r)}}}}function initNode(e){triggerEvent(e,"htmx:beforeProcessNode");let t=getInternalData(e),n=getTriggerSpecs(e);processVerbs(e,t,n)||(getClosestAttributeValue(e,"hx-boost")==="true"?boostElement(e,t,n):hasAttribute(e,"hx-trigger")&&n.forEach(function(o){addTriggerHandler(e,o,t,function(){})})),(e.tagName==="FORM"||getRawAttribute(e,"type")==="submit"&&hasAttribute(e,"form"))&&initButtonTracking(e),t.firstInitCompleted=!0,triggerEvent(e,"htmx:afterProcessNode")}function maybeDeInitAndHash(e){if(!(e instanceof Element))return!1;let t=getInternalData(e),n=attributeHash(e);return t.initHash!==n?(deInitNode(e),t.initHash=n,!0):!1}function processNode(e){if(e=resolveTarget(e),eltIsDisabled(e)){cleanUpElement(e);return}let t=[];maybeDeInitAndHash(e)&&t.push(e),forEach(findElementsToProcess(e),function(n){if(eltIsDisabled(n)){cleanUpElement(n);return}maybeDeInitAndHash(n)&&t.push(n)}),forEach(findHxOnWildcardElements(e),processHxOnWildcard),forEach(t,initNode)}function kebabEventName(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}function makeEvent(e,t){return new CustomEvent(e,{bubbles:!0,cancelable:!0,composed:!0,detail:t})}function triggerErrorEvent(e,t,n){triggerEvent(e,t,mergeObjects({error:t},n))}function ignoreEventForLogging(e){return e==="htmx:afterProcessNode"}function withExtensions(e,t,n){forEach(getExtensions(e,[],n),function(r){try{t(r)}catch(o){logError(o)}})}function logError(e){console.error(e)}function triggerEvent(e,t,n){e=resolveTarget(e),n==null&&(n={}),n.elt=e;let r=makeEvent(t,n);htmx.logger&&!ignoreEventForLogging(t)&&htmx.logger(e,t,n),n.error&&(logError(n.error),triggerEvent(e,"htmx:error",{errorInfo:n}));let o=e.dispatchEvent(r),i=kebabEventName(t);if(o&&i!==t){let s=makeEvent(i,r.detail);o=o&&e.dispatchEvent(s)}return withExtensions(asElement(e),function(s){o=o&&s.onEvent(t,r)!==!1&&!r.defaultPrevented}),o}let currentPathForHistory;function setCurrentPathForHistory(e){currentPathForHistory=e,canAccessLocalStorage()&&sessionStorage.setItem("htmx-current-path-for-history",e)}setCurrentPathForHistory(location.pathname+location.search);function getHistoryElement(){return getDocument().querySelector("[hx-history-elt],[data-hx-history-elt]")||getDocument().body}function saveToHistoryCache(e,t){if(!canAccessLocalStorage())return;let n=cleanInnerHtmlForHistory(t),r=getDocument().title,o=window.scrollY;if(htmx.config.historyCacheSize<=0){sessionStorage.removeItem("htmx-history-cache");return}e=normalizePath(e);let i=parseJSON(sessionStorage.getItem("htmx-history-cache"))||[];for(let a=0;a<i.length;a++)if(i[a].url===e){i.splice(a,1);break}let s={url:e,content:n,title:r,scroll:o};for(triggerEvent(getDocument().body,"htmx:historyItemCreated",{item:s,cache:i}),i.push(s);i.length>htmx.config.historyCacheSize;)i.shift();for(;i.length>0;)try{sessionStorage.setItem("htmx-history-cache",JSON.stringify(i));break}catch(a){triggerErrorEvent(getDocument().body,"htmx:historyCacheError",{cause:a,cache:i}),i.shift()}}function getCachedHistory(e){if(!canAccessLocalStorage())return null;e=normalizePath(e);let t=parseJSON(sessionStorage.getItem("htmx-history-cache"))||[];for(let n=0;n<t.length;n++)if(t[n].url===e)return t[n];return null}function cleanInnerHtmlForHistory(e){let t=htmx.config.requestClass,n=e.cloneNode(!0);return forEach(findAll(n,"."+t),function(r){removeClassFromElement(r,t)}),forEach(findAll(n,"[data-disabled-by-htmx]"),function(r){r.removeAttribute("disabled")}),n.innerHTML}function saveCurrentPageToHistory(){let e=getHistoryElement(),t=currentPathForHistory;canAccessLocalStorage()&&(t=sessionStorage.getItem("htmx-current-path-for-history")),t=t||location.pathname+location.search,getDocument().querySelector('[hx-history="false" i],[data-hx-history="false" i]')||(triggerEvent(getDocument().body,"htmx:beforeHistorySave",{path:t,historyElt:e}),saveToHistoryCache(t,e)),htmx.config.historyEnabled&&history.replaceState({htmx:!0},getDocument().title,location.href)}function pushUrlIntoHistory(e){htmx.config.getCacheBusterParam&&(e=e.replace(/org\.htmx\.cache-buster=[^&]*&?/,""),(endsWith(e,"&")||endsWith(e,"?"))&&(e=e.slice(0,-1))),htmx.config.historyEnabled&&history.pushState({htmx:!0},"",e),setCurrentPathForHistory(e)}function replaceUrlInHistory(e){htmx.config.historyEnabled&&history.replaceState({htmx:!0},"",e),setCurrentPathForHistory(e)}function settleImmediately(e){forEach(e,function(t){t.call(void 0)})}function loadHistoryFromServer(e){let t=new XMLHttpRequest,n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0},r={path:e,xhr:t,historyElt:getHistoryElement(),swapSpec:n};t.open("GET",e,!0),htmx.config.historyRestoreAsHxRequest&&t.setRequestHeader("HX-Request","true"),t.setRequestHeader("HX-History-Restore-Request","true"),t.setRequestHeader("HX-Current-URL",location.href),t.onload=function(){this.status>=200&&this.status<400?(r.response=this.response,triggerEvent(getDocument().body,"htmx:historyCacheMissLoad",r),swap(r.historyElt,r.response,n,{contextElement:r.historyElt,historyRequest:!0}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",{path:e,cacheMiss:!0,serverResponse:r.response})):triggerErrorEvent(getDocument().body,"htmx:historyCacheMissLoadError",r)},triggerEvent(getDocument().body,"htmx:historyCacheMiss",r)&&t.send()}function restoreHistory(e){saveCurrentPageToHistory(),e=e||location.pathname+location.search;let t=getCachedHistory(e);if(t){let n={swapStyle:"innerHTML",swapDelay:0,settleDelay:0,scroll:t.scroll},r={path:e,item:t,historyElt:getHistoryElement(),swapSpec:n};triggerEvent(getDocument().body,"htmx:historyCacheHit",r)&&(swap(r.historyElt,t.content,n,{contextElement:r.historyElt,title:t.title}),setCurrentPathForHistory(r.path),triggerEvent(getDocument().body,"htmx:historyRestore",r))}else htmx.config.refreshOnHistoryMiss?htmx.location.reload(!0):loadHistoryFromServer(e)}function addRequestIndicatorClasses(e){let t=findAttributeTargets(e,"hx-indicator");return t==null&&(t=[e]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.classList.add.call(n.classList,htmx.config.requestClass)}),t}function disableElements(e){let t=findAttributeTargets(e,"hx-disabled-elt");return t==null&&(t=[]),forEach(t,function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||0)+1,n.setAttribute("disabled",""),n.setAttribute("data-disabled-by-htmx","")}),t}function removeRequestIndicators(e,t){forEach(e.concat(t),function(n){let r=getInternalData(n);r.requestCount=(r.requestCount||1)-1}),forEach(e,function(n){getInternalData(n).requestCount===0&&n.classList.remove.call(n.classList,htmx.config.requestClass)}),forEach(t,function(n){getInternalData(n).requestCount===0&&(n.removeAttribute("disabled"),n.removeAttribute("data-disabled-by-htmx"))})}function haveSeenNode(e,t){for(let n=0;n<e.length;n++)if(e[n].isSameNode(t))return!0;return!1}function shouldInclude(e){let t=e;return t.name===""||t.name==null||t.disabled||closest(t,"fieldset[disabled]")||t.type==="button"||t.type==="submit"||t.tagName==="image"||t.tagName==="reset"||t.tagName==="file"?!1:t.type==="checkbox"||t.type==="radio"?t.checked:!0}function addValueToFormData(e,t,n){e!=null&&t!=null&&(Array.isArray(t)?t.forEach(function(r){n.append(e,r)}):n.append(e,t))}function removeValueFromFormData(e,t,n){if(e!=null&&t!=null){let r=n.getAll(e);Array.isArray(t)?r=r.filter(o=>t.indexOf(o)<0):r=r.filter(o=>o!==t),n.delete(e),forEach(r,o=>n.append(e,o))}}function getValueFromInput(e){return e instanceof HTMLSelectElement&&e.multiple?toArray(e.querySelectorAll("option:checked")).map(function(t){return t.value}):e instanceof HTMLInputElement&&e.files?toArray(e.files):e.value}function processInputValue(e,t,n,r,o){if(!(r==null||haveSeenNode(e,r))){if(e.push(r),shouldInclude(r)){let i=getRawAttribute(r,"name");addValueToFormData(i,getValueFromInput(r),t),o&&validateElement(r,n)}r instanceof HTMLFormElement&&(forEach(r.elements,function(i){e.indexOf(i)>=0?removeValueFromFormData(i.name,getValueFromInput(i),t):e.push(i),o&&validateElement(i,n)}),new FormData(r).forEach(function(i,s){i instanceof File&&i.name===""||addValueToFormData(s,i,t)}))}}function validateElement(e,t){let n=e;n.willValidate&&(triggerEvent(n,"htmx:validation:validate"),n.checkValidity()||(triggerEvent(n,"htmx:validation:failed",{message:n.validationMessage,validity:n.validity})&&!t.length&&htmx.config.reportValidityOfForms&&n.reportValidity(),t.push({elt:n,message:n.validationMessage,validity:n.validity})))}function overrideFormData(e,t){for(let n of t.keys())e.delete(n);return t.forEach(function(n,r){e.append(r,n)}),e}function getInputValues(e,t){let n=[],r=new FormData,o=new FormData,i=[],s=getInternalData(e);s.lastButtonClicked&&!bodyContains(s.lastButtonClicked)&&(s.lastButtonClicked=null);let a=e instanceof HTMLFormElement&&e.noValidate!==!0||getAttributeValue(e,"hx-validate")==="true";if(s.lastButtonClicked&&(a=a&&s.lastButtonClicked.formNoValidate!==!0),t!=="get"&&processInputValue(n,o,i,getRelatedForm(e),a),processInputValue(n,r,i,e,a),s.lastButtonClicked||e.tagName==="BUTTON"||e.tagName==="INPUT"&&getRawAttribute(e,"type")==="submit"){let c=s.lastButtonClicked||e,h=getRawAttribute(c,"name");addValueToFormData(h,c.value,o)}let l=findAttributeTargets(e,"hx-include");return forEach(l,function(c){processInputValue(n,r,i,asElement(c),a),matches(c,"form")||forEach(asParentNode(c).querySelectorAll(INPUT_SELECTOR),function(h){processInputValue(n,r,i,h,a)})}),overrideFormData(r,o),{errors:i,formData:r,values:formDataProxy(r)}}function appendParam(e,t,n){e!==""&&(e+="&"),String(n)==="[object Object]"&&(n=JSON.stringify(n));let r=encodeURIComponent(n);return e+=encodeURIComponent(t)+"="+r,e}function urlEncode(e){e=formDataFromObject(e);let t="";return e.forEach(function(n,r){t=appendParam(t,r,n)}),t}function getHeaders(e,t,n){let r={"HX-Request":"true","HX-Trigger":getRawAttribute(e,"id"),"HX-Trigger-Name":getRawAttribute(e,"name"),"HX-Target":getAttributeValue(t,"id"),"HX-Current-URL":location.href};return getValuesForElement(e,"hx-headers",!1,r),n!==void 0&&(r["HX-Prompt"]=n),getInternalData(e).boosted&&(r["HX-Boosted"]="true"),r}function filterValues(e,t){let n=getClosestAttributeValue(t,"hx-params");if(n){if(n==="none")return new FormData;if(n==="*")return e;if(n.indexOf("not ")===0)return forEach(n.slice(4).split(","),function(r){r=r.trim(),e.delete(r)}),e;{let r=new FormData;return forEach(n.split(","),function(o){o=o.trim(),e.has(o)&&e.getAll(o).forEach(function(i){r.append(o,i)})}),r}}else return e}function isAnchorLink(e){return!!getRawAttribute(e,"href")&&getRawAttribute(e,"href").indexOf("#")>=0}function getSwapSpecification(e,t){let n=t||getClosestAttributeValue(e,"hx-swap"),r={swapStyle:getInternalData(e).boosted?"innerHTML":htmx.config.defaultSwapStyle,swapDelay:htmx.config.defaultSwapDelay,settleDelay:htmx.config.defaultSettleDelay};if(htmx.config.scrollIntoViewOnBoost&&getInternalData(e).boosted&&!isAnchorLink(e)&&(r.show="top"),n){let s=splitOnWhitespace(n);if(s.length>0)for(let a=0;a<s.length;a++){let l=s[a];if(l.indexOf("swap:")===0)r.swapDelay=parseInterval(l.slice(5));else if(l.indexOf("settle:")===0)r.settleDelay=parseInterval(l.slice(7));else if(l.indexOf("transition:")===0)r.transition=l.slice(11)==="true";else if(l.indexOf("ignoreTitle:")===0)r.ignoreTitle=l.slice(12)==="true";else if(l.indexOf("scroll:")===0){var o=l.slice(7).split(":");let h=o.pop();var i=o.length>0?o.join(":"):null;r.scroll=h,r.scrollTarget=i}else if(l.indexOf("show:")===0){var o=l.slice(5).split(":");let u=o.pop();var i=o.length>0?o.join(":"):null;r.show=u,r.showTarget=i}else if(l.indexOf("focus-scroll:")===0){let c=l.slice(13);r.focusScroll=c=="true"}else a==0?r.swapStyle=l:logError("Unknown modifier in hx-swap: "+l)}}return r}function usesFormData(e){return getClosestAttributeValue(e,"hx-encoding")==="multipart/form-data"||matches(e,"form")&&getRawAttribute(e,"enctype")==="multipart/form-data"}function encodeParamsForBody(e,t,n){let r=null;return withExtensions(t,function(o){r==null&&(r=o.encodeParameters(e,n,t))}),r??(usesFormData(t)?overrideFormData(new FormData,formDataFromObject(n)):urlEncode(n))}function makeSettleInfo(e){return{tasks:[],elts:[e]}}function updateScrollState(e,t){let n=e[0],r=e[e.length-1];if(t.scroll){var o=null;t.scrollTarget&&(o=asElement(querySelectorExt(n,t.scrollTarget))),t.scroll==="top"&&(n||o)&&(o=o||n,o.scrollTop=0),t.scroll==="bottom"&&(r||o)&&(o=o||r,o.scrollTop=o.scrollHeight),typeof t.scroll=="number"&&getWindow().setTimeout(function(){window.scrollTo(0,t.scroll)},0)}if(t.show){var o=null;if(t.showTarget){let s=t.showTarget;t.showTarget==="window"&&(s="body"),o=asElement(querySelectorExt(n,s))}t.show==="top"&&(n||o)&&(o=o||n,o.scrollIntoView({block:"start",behavior:htmx.config.scrollBehavior})),t.show==="bottom"&&(r||o)&&(o=o||r,o.scrollIntoView({block:"end",behavior:htmx.config.scrollBehavior}))}}function getValuesForElement(e,t,n,r,o){if(r==null&&(r={}),e==null)return r;let i=getAttributeValue(e,t);if(i){let s=i.trim(),a=n;if(s==="unset")return null;s.indexOf("javascript:")===0?(s=s.slice(11),a=!0):s.indexOf("js:")===0&&(s=s.slice(3),a=!0),s.indexOf("{")!==0&&(s="{"+s+"}");let l;a?l=maybeEval(e,function(){return o?Function("event","return ("+s+")").call(e,o):Function("return ("+s+")").call(e)},{}):l=parseJSON(s);for(let c in l)l.hasOwnProperty(c)&&r[c]==null&&(r[c]=l[c])}return getValuesForElement(asElement(parentElt(e)),t,n,r,o)}function maybeEval(e,t,n){return htmx.config.allowEval?t():(triggerErrorEvent(e,"htmx:evalDisallowedError"),n)}function getHXVarsForElement(e,t,n){return getValuesForElement(e,"hx-vars",!0,n,t)}function getHXValsForElement(e,t,n){return getValuesForElement(e,"hx-vals",!1,n,t)}function getExpressionVars(e,t){return mergeObjects(getHXVarsForElement(e,t),getHXValsForElement(e,t))}function safelySetHeaderValue(e,t,n){if(n!==null)try{e.setRequestHeader(t,n)}catch{e.setRequestHeader(t,encodeURIComponent(n)),e.setRequestHeader(t+"-URI-AutoEncoded","true")}}function getPathFromResponse(e){if(e.responseURL)try{let t=new URL(e.responseURL);return t.pathname+t.search}catch{triggerErrorEvent(getDocument().body,"htmx:badResponseUrl",{url:e.responseURL})}}function hasHeader(e,t){return t.test(e.getAllResponseHeaders())}function ajaxHelper(e,t,n){if(e=e.toLowerCase(),n){if(n instanceof Element||typeof n=="string")return issueAjaxRequest(e,t,null,null,{targetOverride:resolveTarget(n)||DUMMY_ELT,returnPromise:!0});{let r=resolveTarget(n.target);return(n.target&&!r||n.source&&!r&&!resolveTarget(n.source))&&(r=DUMMY_ELT),issueAjaxRequest(e,t,resolveTarget(n.source),n.event,{handler:n.handler,headers:n.headers,values:n.values,targetOverride:r,swapOverride:n.swap,select:n.select,returnPromise:!0,push:n.push,replace:n.replace,selectOOB:n.selectOOB})}}else return issueAjaxRequest(e,t,null,null,{returnPromise:!0})}function hierarchyForElt(e){let t=[];for(;e;)t.push(e),e=e.parentElement;return t}function verifyPath(e,t,n){let r=new URL(t,location.protocol!=="about:"?location.href:window.origin),i=(location.protocol!=="about:"?location.origin:window.origin)===r.origin;return htmx.config.selfRequestsOnly&&!i?!1:triggerEvent(e,"htmx:validateUrl",mergeObjects({url:r,sameHost:i},n))}function formDataFromObject(e){if(e instanceof FormData)return e;let t=new FormData;for(let n in e)e.hasOwnProperty(n)&&(e[n]&&typeof e[n].forEach=="function"?e[n].forEach(function(r){t.append(n,r)}):typeof e[n]=="object"&&!(e[n]instanceof Blob)?t.append(n,JSON.stringify(e[n])):t.append(n,e[n]));return t}function formDataArrayProxy(e,t,n){return new Proxy(n,{get:function(r,o){return typeof o=="number"?r[o]:o==="length"?r.length:o==="push"?function(i){r.push(i),e.append(t,i)}:typeof r[o]=="function"?function(){r[o].apply(r,arguments),e.delete(t),r.forEach(function(i){e.append(t,i)})}:r[o]&&r[o].length===1?r[o][0]:r[o]},set:function(r,o,i){return r[o]=i,e.delete(t),r.forEach(function(s){e.append(t,s)}),!0}})}function formDataProxy(e){return new Proxy(e,{get:function(t,n){if(typeof n=="symbol"){let o=Reflect.get(t,n);return typeof o=="function"?function(){return o.apply(e,arguments)}:o}if(n==="toJSON")return()=>Object.fromEntries(e);if(n in t&&typeof t[n]=="function")return function(){return e[n].apply(e,arguments)};let r=e.getAll(n);if(r.length!==0)return r.length===1?r[0]:formDataArrayProxy(t,n,r)},set:function(t,n,r){return typeof n!="string"?!1:(t.delete(n),r&&typeof r.forEach=="function"?r.forEach(function(o){t.append(n,o)}):typeof r=="object"&&!(r instanceof Blob)?t.append(n,JSON.stringify(r)):t.append(n,r),!0)},deleteProperty:function(t,n){return typeof n=="string"&&t.delete(n),!0},ownKeys:function(t){return Reflect.ownKeys(Object.fromEntries(t))},getOwnPropertyDescriptor:function(t,n){return Reflect.getOwnPropertyDescriptor(Object.fromEntries(t),n)}})}function issueAjaxRequest(e,t,n,r,o,i){let s=null,a=null;if(o=o??{},o.returnPromise&&typeof Promise<"u")var l=new Promise(function(p,w){s=p,a=w});n==null&&(n=getDocument().body);let c=o.handler||handleAjaxResponse,h=o.select||null;if(!bodyContains(n))return maybeCall(s),l;let u=o.targetOverride||asElement(getTarget(n));if(u==null||u==DUMMY_ELT)return triggerErrorEvent(n,"htmx:targetError",{target:getClosestAttributeValue(n,"hx-target")}),maybeCall(a),l;let f=getInternalData(n),v=f.lastButtonClicked;if(v){let p=getRawAttribute(v,"formaction");p!=null&&(t=p);let w=getRawAttribute(v,"formmethod");if(w!=null)if(VERBS.includes(w.toLowerCase()))e=w;else return maybeCall(s),l}let d=getClosestAttributeValue(n,"hx-confirm");if(i===void 0&&triggerEvent(n,"htmx:confirm",{target:u,elt:n,path:t,verb:e,triggeringEvent:r,etc:o,issueRequest:function(T){return issueAjaxRequest(e,t,n,r,o,!!T)},question:d})===!1)return maybeCall(s),l;let y=n,m=getClosestAttributeValue(n,"hx-sync"),x=null,b=!1;if(m){let p=m.split(":"),w=p[0].trim();if(w==="this"?y=findThisElement(n,"hx-sync"):y=asElement(querySelectorExt(n,w)),m=(p[1]||"drop").trim(),f=getInternalData(y),m==="drop"&&f.xhr&&f.abortable!==!0)return maybeCall(s),l;if(m==="abort"){if(f.xhr)return maybeCall(s),l;b=!0}else m==="replace"?triggerEvent(y,"htmx:abort"):m.indexOf("queue")===0&&(x=(m.split(" ")[1]||"last").trim())}if(f.xhr)if(f.abortable)triggerEvent(y,"htmx:abort");else{if(x==null){if(r){let p=getInternalData(r);p&&p.triggerSpec&&p.triggerSpec.queue&&(x=p.triggerSpec.queue)}x==null&&(x="last")}return f.queuedRequests==null&&(f.queuedRequests=[]),x==="first"&&f.queuedRequests.length===0?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):x==="all"?f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)}):x==="last"&&(f.queuedRequests=[],f.queuedRequests.push(function(){issueAjaxRequest(e,t,n,r,o)})),maybeCall(s),l}let E=new XMLHttpRequest;f.xhr=E,f.abortable=b;let g=function(){f.xhr=null,f.abortable=!1,f.queuedRequests!=null&&f.queuedRequests.length>0&&f.queuedRequests.shift()()},W=getClosestAttributeValue(n,"hx-prompt");if(W){var q=prompt(W);if(q===null||!triggerEvent(n,"htmx:prompt",{prompt:q,target:u}))return maybeCall(s),g(),l}if(d&&!i&&!confirm(d))return maybeCall(s),g(),l;let H=getHeaders(n,u,q);e!=="get"&&!usesFormData(n)&&(H["Content-Type"]="application/x-www-form-urlencoded"),o.headers&&(H=mergeObjects(H,o.headers));let X=getInputValues(n,e),R=X.errors,$=X.formData;o.values&&overrideFormData($,formDataFromObject(o.values));let re=formDataFromObject(getExpressionVars(n,r)),P=overrideFormData($,re),D=filterValues(P,n);htmx.config.getCacheBusterParam&&e==="get"&&D.set("org.htmx.cache-buster",getRawAttribute(u,"id")||"true"),(t==null||t==="")&&(t=location.href);let k=getValuesForElement(n,"hx-request"),J=getInternalData(n).boosted,I=htmx.config.methodsThatUseUrlParams.indexOf(e)>=0,S={boosted:J,useUrlParams:I,formData:D,parameters:formDataProxy(D),unfilteredFormData:P,unfilteredParameters:formDataProxy(P),headers:H,elt:n,target:u,verb:e,errors:R,withCredentials:o.credentials||k.credentials||htmx.config.withCredentials,timeout:o.timeout||k.timeout||htmx.config.timeout,path:t,triggeringEvent:r};if(!triggerEvent(n,"htmx:configRequest",S))return maybeCall(s),g(),l;if(t=S.path,e=S.verb,H=S.headers,D=formDataFromObject(S.parameters),R=S.errors,I=S.useUrlParams,R&&R.length>0)return triggerEvent(n,"htmx:validation:halted",S),maybeCall(s),g(),l;let z=t.split("#"),oe=z[0],N=z[1],A=t;if(I&&(A=oe,!D.keys().next().done&&(A.indexOf("?")<0?A+="?":A+="&",A+=urlEncode(D),N&&(A+="#"+N))),!verifyPath(n,A,S))return triggerErrorEvent(n,"htmx:invalidPath",S),maybeCall(a),g(),l;if(E.open(e.toUpperCase(),A,!0),E.overrideMimeType("text/html"),E.withCredentials=S.withCredentials,E.timeout=S.timeout,!k.noHeaders){for(let p in H)if(H.hasOwnProperty(p)){let w=H[p];safelySetHeaderValue(E,p,w)}}let C={xhr:E,target:u,requestConfig:S,etc:o,boosted:J,select:h,pathInfo:{requestPath:t,finalRequestPath:A,responsePath:null,anchor:N}};if(E.onload=function(){try{let p=hierarchyForElt(n);if(C.pathInfo.responsePath=getPathFromResponse(E),c(n,C),C.keepIndicators!==!0&&removeRequestIndicators(L,O),triggerEvent(n,"htmx:afterRequest",C),triggerEvent(n,"htmx:afterOnLoad",C),!bodyContains(n)){let w=null;for(;p.length>0&&w==null;){let T=p.shift();bodyContains(T)&&(w=T)}w&&(triggerEvent(w,"htmx:afterRequest",C),triggerEvent(w,"htmx:afterOnLoad",C))}maybeCall(s)}catch(p){throw triggerErrorEvent(n,"htmx:onLoadError",mergeObjects({error:p},C)),p}finally{g()}},E.onerror=function(){removeRequestIndicators(L,O),triggerErrorEvent(n,"htmx:afterRequest",C),triggerErrorEvent(n,"htmx:sendError",C),maybeCall(a),g()},E.onabort=function(){removeRequestIndicators(L,O),triggerErrorEvent(n,"htmx:afterRequest",C),triggerErrorEvent(n,"htmx:sendAbort",C),maybeCall(a),g()},E.ontimeout=function(){removeRequestIndicators(L,O),triggerErrorEvent(n,"htmx:afterRequest",C),triggerErrorEvent(n,"htmx:timeout",C),maybeCall(a),g()},!triggerEvent(n,"htmx:beforeRequest",C))return maybeCall(s),g(),l;var L=addRequestIndicatorClasses(n),O=disableElements(n);forEach(["loadstart","loadend","progress","abort"],function(p){forEach([E,E.upload],function(w){w.addEventListener(p,function(T){triggerEvent(n,"htmx:xhr:"+p,{lengthComputable:T.lengthComputable,loaded:T.loaded,total:T.total})})})}),triggerEvent(n,"htmx:beforeSend",C);let ie=I?null:encodeParamsForBody(E,n,D);return E.send(ie),l}function determineHistoryUpdates(e,t){let n=t.xhr,r=null,o=null;if(hasHeader(n,/HX-Push:/i)?(r=n.getResponseHeader("HX-Push"),o="push"):hasHeader(n,/HX-Push-Url:/i)?(r=n.getResponseHeader("HX-Push-Url"),o="push"):hasHeader(n,/HX-Replace-Url:/i)&&(r=n.getResponseHeader("HX-Replace-Url"),o="replace"),r)return r==="false"?{}:{type:o,path:r};let i=t.pathInfo.finalRequestPath,s=t.pathInfo.responsePath,a=t.etc.push||getClosestAttributeValue(e,"hx-push-url"),l=t.etc.replace||getClosestAttributeValue(e,"hx-replace-url"),c=getInternalData(e).boosted,h=null,u=null;return a?(h="push",u=a):l?(h="replace",u=l):c&&(h="push",u=s||i),u?u==="false"?{}:(u==="true"&&(u=s||i),t.pathInfo.anchor&&u.indexOf("#")===-1&&(u=u+"#"+t.pathInfo.anchor),{type:h,path:u}):{}}function codeMatches(e,t){var n=new RegExp(e.code);return n.test(t.toString(10))}function resolveResponseHandling(e){for(var t=0;t<htmx.config.responseHandling.length;t++){var n=htmx.config.responseHandling[t];if(codeMatches(n,e.status))return n}return{swap:!1}}function handleTitle(e){if(e){let t=find("title");t?t.textContent=e:window.document.title=e}}function resolveRetarget(e,t){if(t==="this")return e;let n=asElement(querySelectorExt(e,t));if(n==null)throw triggerErrorEvent(e,"htmx:targetError",{target:t}),new Error(`Invalid re-target ${t}`);return n}function handleAjaxResponse(e,t){let n=t.xhr,r=t.target,o=t.etc,i=t.select;if(!triggerEvent(e,"htmx:beforeOnLoad",t))return;if(hasHeader(n,/HX-Trigger:/i)&&handleTriggerHeader(n,"HX-Trigger",e),hasHeader(n,/HX-Location:/i)){let b=n.getResponseHeader("HX-Location");var s={};b.indexOf("{")===0&&(s=parseJSON(b),b=s.path,delete s.path),s.push=s.push||"true",ajaxHelper("get",b,s);return}let a=hasHeader(n,/HX-Refresh:/i)&&n.getResponseHeader("HX-Refresh")==="true";if(hasHeader(n,/HX-Redirect:/i)){t.keepIndicators=!0,htmx.location.href=n.getResponseHeader("HX-Redirect"),a&&htmx.location.reload();return}if(a){t.keepIndicators=!0,htmx.location.reload();return}let l=determineHistoryUpdates(e,t),c=resolveResponseHandling(n),h=c.swap,u=!!c.error,f=htmx.config.ignoreTitle||c.ignoreTitle,v=c.select;c.target&&(t.target=resolveRetarget(e,c.target));var d=o.swapOverride;d==null&&c.swapOverride&&(d=c.swapOverride),hasHeader(n,/HX-Retarget:/i)&&(t.target=resolveRetarget(e,n.getResponseHeader("HX-Retarget"))),hasHeader(n,/HX-Reswap:/i)&&(d=n.getResponseHeader("HX-Reswap"));var y=n.response,m=mergeObjects({shouldSwap:h,serverResponse:y,isError:u,ignoreTitle:f,selectOverride:v,swapOverride:d},t);if(!(c.event&&!triggerEvent(r,c.event,m))&&triggerEvent(r,"htmx:beforeSwap",m)){if(r=m.target,y=m.serverResponse,u=m.isError,f=m.ignoreTitle,v=m.selectOverride,d=m.swapOverride,t.target=r,t.failed=u,t.successful=!u,m.shouldSwap){n.status===286&&cancelPolling(e),withExtensions(e,function(g){y=g.transformResponse(y,n,e)}),l.type&&saveCurrentPageToHistory();var x=getSwapSpecification(e,d);x.hasOwnProperty("ignoreTitle")||(x.ignoreTitle=f),r.classList.add(htmx.config.swappingClass),i&&(v=i),hasHeader(n,/HX-Reselect:/i)&&(v=n.getResponseHeader("HX-Reselect"));let b=o.selectOOB||getClosestAttributeValue(e,"hx-select-oob"),E=getClosestAttributeValue(e,"hx-select");swap(r,y,x,{select:v==="unset"?null:v||E,selectOOB:b,eventInfo:t,anchor:t.pathInfo.anchor,contextElement:e,afterSwapCallback:function(){if(hasHeader(n,/HX-Trigger-After-Swap:/i)){let g=e;bodyContains(e)||(g=getDocument().body),handleTriggerHeader(n,"HX-Trigger-After-Swap",g)}},afterSettleCallback:function(){if(hasHeader(n,/HX-Trigger-After-Settle:/i)){let g=e;bodyContains(e)||(g=getDocument().body),handleTriggerHeader(n,"HX-Trigger-After-Settle",g)}},beforeSwapCallback:function(){l.type&&(triggerEvent(getDocument().body,"htmx:beforeHistoryUpdate",mergeObjects({history:l},t)),l.type==="push"?(pushUrlIntoHistory(l.path),triggerEvent(getDocument().body,"htmx:pushedIntoHistory",{path:l.path})):(replaceUrlInHistory(l.path),triggerEvent(getDocument().body,"htmx:replacedInHistory",{path:l.path})))}})}u&&triggerErrorEvent(e,"htmx:responseError",mergeObjects({error:"Response Status Error Code "+n.status+" from "+t.pathInfo.requestPath},t))}}let extensions={};function extensionBase(){return{init:function(e){return null},getSelectors:function(){return null},onEvent:function(e,t){return!0},transformResponse:function(e,t,n){return e},isInlineSwap:function(e){return!1},handleSwap:function(e,t,n,r){return!1},encodeParameters:function(e,t,n){return null}}}function defineExtension(e,t){t.init&&t.init(internalAPI),extensions[e]=mergeObjects(extensionBase(),t)}function removeExtension(e){delete extensions[e]}function getExtensions(e,t,n){if(t==null&&(t=[]),e==null)return t;n==null&&(n=[]);let r=getAttributeValue(e,"hx-ext");return r&&forEach(r.split(","),function(o){if(o=o.replace(/ /g,""),o.slice(0,7)=="ignore:"){n.push(o.slice(7));return}if(n.indexOf(o)<0){let i=extensions[o];i&&t.indexOf(i)<0&&t.push(i)}}),getExtensions(asElement(parentElt(e)),t,n)}var isReady=!1;getDocument().addEventListener("DOMContentLoaded",function(){isReady=!0});function ready(e){isReady||getDocument().readyState==="complete"?e():getDocument().addEventListener("DOMContentLoaded",e)}function insertIndicatorStyles(){if(htmx.config.includeIndicatorStyles!==!1){let e=htmx.config.inlineStyleNonce?` nonce="${htmx.config.inlineStyleNonce}"`:"",t=htmx.config.indicatorClass,n=htmx.config.requestClass;getDocument().head.insertAdjacentHTML("beforeend",`<style${e}>.${t}{opacity:0;visibility: hidden} .${n} .${t}, .${n}.${t}{opacity:1;visibility: visible;transition: opacity 200ms ease-in}</style>`)}}function getMetaConfig(){let e=getDocument().querySelector('meta[name="htmx-config"]');return e?parseJSON(e.content):null}function mergeMetaConfig(){let e=getMetaConfig();e&&(htmx.config=mergeObjects(htmx.config,e))}return ready(function(){mergeMetaConfig(),insertIndicatorStyles();let e=getDocument().body;processNode(e);let t=getDocument().querySelectorAll("[hx-trigger='restored'],[data-hx-trigger='restored']");e.addEventListener("htmx:abort",function(r){let o=r.detail.elt||r.target,i=getInternalData(o);i&&i.xhr&&i.xhr.abort()});let n=window.onpopstate?window.onpopstate.bind(window):null;window.onpopstate=function(r){r.state&&r.state.htmx?(restoreHistory(),forEach(t,function(o){triggerEvent(o,"htmx:restored",{document:getDocument(),triggerEvent})})):n&&n(r)},getWindow().setTimeout(function(){triggerEvent(e,"htmx:load",{}),e=null},0)}),htmx})(),F=se;(function(){let e;F.defineExtension("json-enc",{init:function(t){e=t},onEvent:function(t,n){t==="htmx:configRequest"&&(n.detail.headers["Content-Type"]="application/json")},encodeParameters:function(t,n,r){t.overrideMimeType("text/json");let o={};n.forEach(function(s,a){Object.hasOwn(o,a)?(Array.isArray(o[a])||(o[a]=[o[a]]),o[a].push(s)):o[a]=s});let i=e.getExpressionVars(r);return Object.keys(o).forEach(function(s){o[s]=Object.hasOwn(i,s)?i[s]:o[s]}),JSON.stringify(o)}})})();var K=document.createElement("template");K.innerHTML=`
2
2
<slot></slot>
3
3
4
4
<ul class="menu" part="menu"></ul>
···
92
92
<span class="handle" part="handle"></span>
93
93
</button>
94
94
</li>
95
95
-
`;function Y(e){return e.cloneNode(!0)}var N=class extends HTMLElement{static tag="actor-typeahead";static define(t=this.tag){this.tag=t;let n=customElements.getName(this);if(n&&n!==t)return console.warn(`${this.name} already defined as <${n}>!`);let r=customElements.get(t);if(r&&r!==this)return console.warn(`<${t}> already defined as ${r.name}!`);customElements.define(t,this)}static{let t=new URL(import.meta.url).searchParams.get("tag")||this.tag;t!=="none"&&this.define(t)}#n=this.attachShadow({mode:"closed"});#r=[];#e=-1;#o=!1;constructor(){super(),this.#n.append(Y(K).content),this.#t(),this.addEventListener("input",this),this.addEventListener("focusout",this),this.addEventListener("keydown",this),this.#n.addEventListener("pointerdown",this),this.#n.addEventListener("pointerup",this),this.#n.addEventListener("click",this)}get#i(){let t=Number.parseInt(this.getAttribute("rows")??"");return Number.isNaN(t)?5:t}handleEvent(t){switch(t.type){case"input":this.#a(t);break;case"keydown":this.#s(t);break;case"focusout":this.#l(t);break;case"pointerdown":this.#c(t);break;case"pointerup":this.#u(t);break}}#s(t){switch(t.key){case"ArrowDown":t.preventDefault(),this.#e=Math.min(this.#e+1,this.#i-1),this.#t();break;case"PageDown":t.preventDefault(),this.#e=this.#i-1,this.#t();break;case"ArrowUp":t.preventDefault(),this.#e=Math.max(this.#e-1,0),this.#t();break;case"PageUp":t.preventDefault(),this.#e=0,this.#t();break;case"Escape":t.preventDefault(),this.#r=[],this.#e=-1,this.#t();break;case"Enter":t.preventDefault(),this.#n.querySelectorAll("button")[this.#e]?.dispatchEvent(new PointerEvent("pointerup",{bubbles:!0}));break}}async#a(t){let n=t.target?.value;if(!n){this.#r=[],this.#t();return}let r=this.getAttribute("host")??"https://public.api.bsky.app",o=new URL("xrpc/app.bsky.actor.searchActorsTypeahead",r);o.searchParams.set("q",n),o.searchParams.set("limit",`${this.#i}`);let s=await(await fetch(o)).json();this.#r=s.actors,this.#e=-1,this.#t()}async#l(t){this.#o||(this.#r=[],this.#e=-1,this.#t())}#t(){let t=document.createDocumentFragment(),n=-1;for(let r of this.#r){let o=Y(G).content,i=o.querySelector("button");i&&(i.dataset.handle=r.handle,++n===this.#e&&(i.dataset.active="true"));let s=o.querySelector("img");s&&r.avatar&&(s.src=r.avatar);let a=o.querySelector(".handle");a&&(a.textContent=r.handle),t.append(o)}this.#n.querySelector(".menu")?.replaceChildren(...t.children)}#c(t){this.#o=!0}#u(t){this.#o=!1,this.querySelector("input")?.focus();let n=t.target?.closest("button"),r=this.querySelector("input");!r||!n||(r.value=n.dataset.handle||"",this.#r=[],this.#t())}};function Z(){return localStorage.getItem("theme")||"system"}function ae(e){return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function U(){let e=Z(),n=ae(e)==="dark";document.documentElement.classList.toggle("dark",n),document.documentElement.setAttribute("data-theme",n?"dark":"light"),le(e)}function ee(e){localStorage.setItem("theme",e),U(),ce()}function le(e){let t={system:"sun-moon",light:"sun",dark:"moon"};document.querySelectorAll("[data-theme-icon] use").forEach(n=>{n.setAttribute("href",`/icons.svg#${t[e]||"sun-moon"}`)}),document.querySelectorAll(".theme-option").forEach(n=>{let r=n.dataset.value===e,o=n.querySelector(".theme-check");o&&(o.style.visibility=r?"visible":"hidden")})}function ce(){document.querySelectorAll("[data-theme-toggle]").forEach(e=>{let t=e.closest("details");t&&t.removeAttribute("open")})}window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Z()==="system"&&U()});function ue(){let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(e.classList.toggle("expanded"),e.classList.contains("expanded")&&t.focus())}function B(){let e=document.querySelector(".nav-search-wrapper");e&&e.classList.remove("expanded")}document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(document.addEventListener("keydown",n=>{n.key==="Escape"&&e.classList.contains("expanded")&&B()}),document.addEventListener("click",n=>{e.classList.contains("expanded")&&!e.contains(n.target)&&B()}))});function te(e,t){!t&&typeof event<"u"&&(t=event.target.closest("button")),navigator.clipboard.writeText(e).then(()=>{if(!t)return;let n=t.innerHTML;t.innerHTML='<svg class="icon size-4" aria-hidden="true"><use href="/icons.svg#check"></use></svg> Copied!',setTimeout(()=>{t.innerHTML=n},2e3)}).catch(n=>{console.error("Failed to copy:",n)})}document.addEventListener("DOMContentLoaded",()=>{document.addEventListener("click",e=>{let t=e.target.closest("button[data-cmd]");if(t){te(t.getAttribute("data-cmd"),t);return}if(e.target.closest("a, button, input, .cmd"))return;let n=e.target.closest("[data-href]");n&&(window.location=n.getAttribute("data-href"))})});function fe(e){let t=Math.floor((new Date-new Date(e))/1e3),n={year:31536e3,month:2592e3,week:604800,day:86400,hour:3600,minute:60,second:1};for(let[r,o]of Object.entries(n)){let i=Math.floor(t/o);if(i>=1)return i===1?`1 ${r} ago`:`${i} ${r}s ago`}return"just now"}function _(){document.querySelectorAll("time[datetime]").forEach(e=>{let t=e.getAttribute("datetime");if(t&&!e.dataset.noUpdate){let n=fe(t);e.textContent!==n&&(e.textContent=n)}})}document.addEventListener("DOMContentLoaded",()=>{_(),U(),document.querySelectorAll("[data-theme-menu]").forEach(e=>{e.querySelectorAll(".theme-option").forEach(t=>{t.addEventListener("click",()=>{ee(t.dataset.value)})})}),document.addEventListener("click",e=>{let t=e.target.closest("details.dropdown");document.querySelectorAll("details.dropdown[open]").forEach(n=>{n!==t&&n.removeAttribute("open")})})});document.addEventListener("htmx:afterSwap",_);setInterval(_,6e4);function de(){let e=document.getElementById("show-offline-toggle"),t=document.querySelector(".manifests-list");!e||!t||(localStorage.setItem("showOfflineManifests",e.checked),e.checked?t.classList.add("show-offline"):t.classList.remove("show-offline"))}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("show-offline-toggle");if(!e)return;let t=localStorage.getItem("showOfflineManifests")==="true";e.checked=t;let n=document.querySelector(".manifests-list");n&&(t?n.classList.add("show-offline"):n.classList.remove("show-offline"))});async function he(e,t,n){try{let r=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!1})});if(r.status===409){let o=await r.json();me(e,t,n,o.tags)}else if(r.ok)ne(n);else{let o=await r.text();alert(`Failed to delete manifest: ${o}`)}}catch(r){console.error("Error deleting manifest:",r),alert(`Error deleting manifest: ${r.message}`)}}function me(e,t,n,r){let o=document.getElementById("manifest-delete-modal"),i=document.getElementById("manifest-delete-tags"),s=document.getElementById("confirm-manifest-delete-btn");i.innerHTML="",r.forEach(a=>{let l=document.createElement("li");l.textContent=a,i.appendChild(l)}),s.onclick=()=>ge(e,t,n),o.style.display="flex"}function j(){let e=document.getElementById("manifest-delete-modal");e.style.display="none"}async function ge(e,t,n){let r=document.getElementById("confirm-manifest-delete-btn"),o=r.textContent;try{r.disabled=!0,r.textContent="Deleting...";let i=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!0})});if(i.ok)j(),ne(n),location.reload();else{let s=await i.text();alert(`Failed to delete manifest: ${s}`),r.disabled=!1,r.textContent=o}}catch(i){console.error("Error deleting manifest:",i),alert(`Error deleting manifest: ${i.message}`),r.disabled=!1,r.textContent=o}}function ne(e){let t=document.getElementById(`manifest-${e}`);t&&t.remove()}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("manifest-delete-modal");e&&e.addEventListener("click",t=>{t.target===e&&j()})});async function pe(e,t){let n=document.getElementById("vuln-detail-modal"),r=document.getElementById("vuln-modal-body");if(!(!n||!r)){r.innerHTML='<div class="flex justify-center py-8"><span class="loading loading-spinner loading-lg"></span></div>',n.showModal();try{let o=await fetch(`/api/vuln-details?digest=${encodeURIComponent(e)}&holdEndpoint=${encodeURIComponent(t)}`);r.innerHTML=await o.text()}catch{r.innerHTML='<p class="text-error">Failed to load vulnerability details</p>'}}}var V=class{constructor(t){this.input=t,this.typeahead=t.closest("actor-typeahead"),this.dropdown=null,this.currentFocus=-1,this.typeaheadClosed=!1,this.init()}init(){this.createDropdown(),this.input.addEventListener("focus",()=>this.handleFocus()),this.input.addEventListener("input",()=>this.handleInput()),this.input.addEventListener("keydown",t=>this.handleKeydown(t)),document.addEventListener("click",t=>{!this.input.contains(t.target)&&!this.dropdown.contains(t.target)&&this.hideDropdown()})}createDropdown(){this.dropdown=document.createElement("div"),this.dropdown.className="recent-accounts-dropdown",this.dropdown.style.display="none",this.typeahead?this.typeahead.insertAdjacentElement("afterend",this.dropdown):this.input.insertAdjacentElement("afterend",this.dropdown)}handleFocus(){this.input.value.trim().length<1&&this.showRecentAccounts()}handleInput(){this.input.value.trim().length>=1&&this.hideDropdown(),this.typeaheadClosed=!1}showRecentAccounts(){let t=this.getRecentAccounts();if(t.length===0){this.hideDropdown();return}this.dropdown.innerHTML="",this.currentFocus=-1;let n=document.createElement("div");n.className="recent-accounts-header",n.textContent="Recent accounts",this.dropdown.appendChild(n),t.forEach((r,o)=>{let i=document.createElement("div");i.className="recent-accounts-item",i.dataset.index=o,i.dataset.handle=r,i.textContent=r,i.addEventListener("click",()=>this.selectItem(r)),this.dropdown.appendChild(i)}),this.dropdown.style.display="block"}selectItem(t){this.input.value=t,this.hideDropdown(),this.input.focus()}hideDropdown(){this.dropdown.style.display="none",this.currentFocus=-1}handleKeydown(t){if(t.key==="Enter"&&this.input.value.trim().length>=2&&(this.typeaheadClosed=!0),t.key==="Tab"&&this.input.value.trim().length>=2&&!this.typeaheadClosed){t.preventDefault();let o=t.shiftKey?"ArrowUp":"ArrowDown",i=new KeyboardEvent("keydown",{key:o,bubbles:!0,cancelable:!0});this.typeahead.dispatchEvent(i);return}if(this.dropdown.style.display==="none")return;let n=this.dropdown.querySelectorAll(".recent-accounts-item");t.key==="ArrowDown"?(t.preventDefault(),this.currentFocus++,this.currentFocus>=n.length&&(this.currentFocus=0),this.updateFocus(n)):t.key==="ArrowUp"?(t.preventDefault(),this.currentFocus--,this.currentFocus<0&&(this.currentFocus=n.length-1),this.updateFocus(n)):t.key==="Enter"&&this.currentFocus>-1&&n[this.currentFocus]?(t.preventDefault(),this.selectItem(n[this.currentFocus].dataset.handle)):t.key==="Escape"&&this.hideDropdown()}updateFocus(t){t.forEach((n,r)=>{n.classList.toggle("focused",r===this.currentFocus)})}getRecentAccounts(){try{let t=localStorage.getItem("atcr_recent_handles");return t?JSON.parse(t):[]}catch{return[]}}saveRecentAccount(t){if(t)try{let n=this.getRecentAccounts();n=n.filter(r=>r!==t),n.unshift(t),n=n.slice(0,5),localStorage.setItem("atcr_recent_handles",JSON.stringify(n))}catch(n){console.error("Failed to save recent account:",n)}}};document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("login-form"),t=document.getElementById("handle");e&&t&&new V(t)});document.addEventListener("DOMContentLoaded",()=>{let e=document.cookie.split("; ").find(n=>n.startsWith("atcr_login_handle="));if(!e)return;let t=decodeURIComponent(e.split("=")[1]);if(t){try{let n="atcr_recent_handles",r=JSON.parse(localStorage.getItem(n)||"[]");r=r.filter(o=>o!==t),r.unshift(t),r=r.slice(0,5),localStorage.setItem(n,JSON.stringify(r))}catch(n){console.error("Failed to save recent account:",n)}document.cookie="atcr_login_handle=; path=/; max-age=0"}});function Q(){let e=document.getElementById("featured-carousel"),t=document.getElementById("carousel-prev"),n=document.getElementById("carousel-next");if(!e)return;let r=Array.from(e.querySelectorAll(".carousel-item"));if(r.length===0)return;let o=null,i=5e3,s=0,a=0,l=0;function c(){let b=r[0];if(!b)return;let E=getComputedStyle(e),g=parseFloat(E.gap)||24;s=b.offsetWidth+g,a=e.offsetWidth,l=e.scrollWidth}requestAnimationFrame(()=>{requestAnimationFrame(()=>{c(),m()})});let h;window.addEventListener("resize",()=>{clearTimeout(h),h=setTimeout(c,150)});function u(){return s||c(),s}function f(){return(!a||!s)&&c(),Math.round(a/s)||1}function v(){return(!l||!a)&&c(),l-a}function d(){let b=u(),E=v(),g=e.scrollLeft;g>=E-10?e.scrollTo({left:0,behavior:"smooth"}):e.scrollTo({left:g+b,behavior:"smooth"})}function y(){let b=u(),E=v(),g=e.scrollLeft;g<=10?e.scrollTo({left:E,behavior:"smooth"}):e.scrollTo({left:g-b,behavior:"smooth"})}t&&t.addEventListener("click",()=>{x(),y(),m()}),n&&n.addEventListener("click",()=>{x(),d(),m()});function m(){o||r.length<=f()||(o=setInterval(d,i))}function x(){o&&(clearInterval(o),o=null)}e.addEventListener("mouseenter",x),e.addEventListener("mouseleave",m)}document.addEventListener("DOMContentLoaded",()=>{"requestIdleCallback"in window?requestIdleCallback(Q,{timeout:2e3}):setTimeout(Q,100)});window.setTheme=ee;window.toggleSearch=ue;window.closeSearch=B;window.copyToClipboard=te;window.toggleOfflineManifests=de;window.deleteManifest=he;window.closeManifestDeleteModal=j;window.openVulnDetails=pe;window.htmx=F;
95
95
+
`;function Y(e){return e.cloneNode(!0)}var M=class extends HTMLElement{static tag="actor-typeahead";static define(t=this.tag){this.tag=t;let n=customElements.getName(this);if(n&&n!==t)return console.warn(`${this.name} already defined as <${n}>!`);let r=customElements.get(t);if(r&&r!==this)return console.warn(`<${t}> already defined as ${r.name}!`);customElements.define(t,this)}static{let t=new URL(import.meta.url).searchParams.get("tag")||this.tag;t!=="none"&&this.define(t)}#n=this.attachShadow({mode:"closed"});#r=[];#e=-1;#o=!1;constructor(){super(),this.#n.append(Y(K).content),this.#t(),this.addEventListener("input",this),this.addEventListener("focusout",this),this.addEventListener("keydown",this),this.#n.addEventListener("pointerdown",this),this.#n.addEventListener("pointerup",this),this.#n.addEventListener("click",this)}get#i(){let t=Number.parseInt(this.getAttribute("rows")??"");return Number.isNaN(t)?5:t}handleEvent(t){switch(t.type){case"input":this.#a(t);break;case"keydown":this.#s(t);break;case"focusout":this.#l(t);break;case"pointerdown":this.#c(t);break;case"pointerup":this.#u(t);break}}#s(t){switch(t.key){case"ArrowDown":t.preventDefault(),this.#e=Math.min(this.#e+1,this.#i-1),this.#t();break;case"PageDown":t.preventDefault(),this.#e=this.#i-1,this.#t();break;case"ArrowUp":t.preventDefault(),this.#e=Math.max(this.#e-1,0),this.#t();break;case"PageUp":t.preventDefault(),this.#e=0,this.#t();break;case"Escape":t.preventDefault(),this.#r=[],this.#e=-1,this.#t();break;case"Enter":t.preventDefault(),this.#n.querySelectorAll("button")[this.#e]?.dispatchEvent(new PointerEvent("pointerup",{bubbles:!0}));break}}async#a(t){let n=t.target?.value;if(!n){this.#r=[],this.#t();return}let r=this.getAttribute("host")??"https://public.api.bsky.app",o=new URL("xrpc/app.bsky.actor.searchActorsTypeahead",r);o.searchParams.set("q",n),o.searchParams.set("limit",`${this.#i}`);let s=await(await fetch(o)).json();this.#r=s.actors,this.#e=-1,this.#t()}async#l(t){this.#o||(this.#r=[],this.#e=-1,this.#t())}#t(){let t=document.createDocumentFragment(),n=-1;for(let r of this.#r){let o=Y(G).content,i=o.querySelector("button");i&&(i.dataset.handle=r.handle,++n===this.#e&&(i.dataset.active="true"));let s=o.querySelector("img");s&&r.avatar&&(s.src=r.avatar);let a=o.querySelector(".handle");a&&(a.textContent=r.handle),t.append(o)}this.#n.querySelector(".menu")?.replaceChildren(...t.children)}#c(t){this.#o=!0}#u(t){this.#o=!1,this.querySelector("input")?.focus();let n=t.target?.closest("button"),r=this.querySelector("input");!r||!n||(r.value=n.dataset.handle||"",this.#r=[],this.#t())}};function Z(){return localStorage.getItem("theme")||"system"}function ae(e){return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function U(){let e=Z(),n=ae(e)==="dark";document.documentElement.classList.toggle("dark",n),document.documentElement.setAttribute("data-theme",n?"dark":"light"),le(e)}function ee(e){localStorage.setItem("theme",e),U(),ce()}function le(e){let t={system:"sun-moon",light:"sun",dark:"moon"};document.querySelectorAll("[data-theme-icon] use").forEach(n=>{n.setAttribute("href",`/icons.svg#${t[e]||"sun-moon"}`)}),document.querySelectorAll(".theme-option").forEach(n=>{let r=n.dataset.value===e,o=n.querySelector(".theme-check");o&&(o.style.visibility=r?"visible":"hidden")})}function ce(){document.querySelectorAll("[data-theme-toggle]").forEach(e=>{let t=e.closest("details");t&&t.removeAttribute("open")})}window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{Z()==="system"&&U()});function ue(){let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(e.classList.toggle("expanded"),e.classList.contains("expanded")&&t.focus())}function B(){let e=document.querySelector(".nav-search-wrapper");e&&e.classList.remove("expanded")}document.addEventListener("DOMContentLoaded",()=>{let e=document.querySelector(".nav-search-wrapper"),t=document.getElementById("nav-search-input");!e||!t||(document.addEventListener("keydown",n=>{if(n.key==="Escape"&&e.classList.contains("expanded")&&B(),n.key==="/"&&!e.classList.contains("expanded")){let r=n.target.tagName;if(r==="INPUT"||r==="TEXTAREA"||n.target.isContentEditable)return;n.preventDefault(),e.classList.add("expanded"),t.focus()}}),document.addEventListener("click",n=>{e.classList.contains("expanded")&&!e.contains(n.target)&&B()}))});function te(e,t){!t&&typeof event<"u"&&(t=event.target.closest("button")),navigator.clipboard.writeText(e).then(()=>{if(!t)return;let n=t.innerHTML;t.innerHTML='<svg class="icon size-4" aria-hidden="true"><use href="/icons.svg#check"></use></svg> Copied!',setTimeout(()=>{t.innerHTML=n},2e3)}).catch(n=>{console.error("Failed to copy:",n)})}document.addEventListener("DOMContentLoaded",()=>{document.addEventListener("click",e=>{let t=e.target.closest("button[data-cmd]");if(t){te(t.getAttribute("data-cmd"),t);return}if(e.target.closest("a, button, input, .cmd"))return;let n=e.target.closest("[data-href]");n&&(window.location=n.getAttribute("data-href"))})});function fe(e){let t=Math.floor((new Date-new Date(e))/1e3),n={year:31536e3,month:2592e3,week:604800,day:86400,hour:3600,minute:60,second:1};for(let[r,o]of Object.entries(n)){let i=Math.floor(t/o);if(i>=1)return i===1?`1 ${r} ago`:`${i} ${r}s ago`}return"just now"}function _(){document.querySelectorAll("time[datetime]").forEach(e=>{let t=e.getAttribute("datetime");if(t&&!e.dataset.noUpdate){let n=fe(t);e.textContent!==n&&(e.textContent=n)}})}document.addEventListener("DOMContentLoaded",()=>{_(),U(),document.querySelectorAll("[data-theme-menu]").forEach(e=>{e.querySelectorAll(".theme-option").forEach(t=>{t.addEventListener("click",()=>{ee(t.dataset.value)})})}),document.addEventListener("click",e=>{let t=e.target.closest("details.dropdown");document.querySelectorAll("details.dropdown[open]").forEach(n=>{n!==t&&n.removeAttribute("open")})})});document.addEventListener("htmx:afterSwap",_);setInterval(_,6e4);function de(){let e=document.getElementById("show-offline-toggle"),t=document.querySelector(".manifests-list");!e||!t||(localStorage.setItem("showOfflineManifests",e.checked),e.checked?t.classList.add("show-offline"):t.classList.remove("show-offline"))}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("show-offline-toggle");if(!e)return;let t=localStorage.getItem("showOfflineManifests")==="true";e.checked=t;let n=document.querySelector(".manifests-list");n&&(t?n.classList.add("show-offline"):n.classList.remove("show-offline"))});async function he(e,t,n){try{let r=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!1})});if(r.status===409){let o=await r.json();me(e,t,n,o.tags)}else if(r.ok)ne(n);else{let o=await r.text();alert(`Failed to delete manifest: ${o}`)}}catch(r){console.error("Error deleting manifest:",r),alert(`Error deleting manifest: ${r.message}`)}}function me(e,t,n,r){let o=document.getElementById("manifest-delete-modal"),i=document.getElementById("manifest-delete-tags"),s=document.getElementById("confirm-manifest-delete-btn");i.innerHTML="",r.forEach(a=>{let l=document.createElement("li");l.textContent=a,i.appendChild(l)}),s.onclick=()=>ge(e,t,n),o.style.display="flex"}function j(){let e=document.getElementById("manifest-delete-modal");e.style.display="none"}async function ge(e,t,n){let r=document.getElementById("confirm-manifest-delete-btn"),o=r.textContent;try{r.disabled=!0,r.textContent="Deleting...";let i=await fetch("/api/manifests",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({repo:e,digest:t,confirm:!0})});if(i.ok)j(),ne(n),location.reload();else{let s=await i.text();alert(`Failed to delete manifest: ${s}`),r.disabled=!1,r.textContent=o}}catch(i){console.error("Error deleting manifest:",i),alert(`Error deleting manifest: ${i.message}`),r.disabled=!1,r.textContent=o}}function ne(e){let t=document.getElementById(`manifest-${e}`);t&&t.remove()}document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("manifest-delete-modal");e&&e.addEventListener("click",t=>{t.target===e&&j()})});async function pe(e,t){let n=document.getElementById("vuln-detail-modal"),r=document.getElementById("vuln-modal-body");if(!(!n||!r)){r.innerHTML='<div class="flex justify-center py-8"><span class="loading loading-spinner loading-lg"></span></div>',n.showModal();try{let o=await fetch(`/api/vuln-details?digest=${encodeURIComponent(e)}&holdEndpoint=${encodeURIComponent(t)}`);r.innerHTML=await o.text()}catch{r.innerHTML='<p class="text-error">Failed to load vulnerability details</p>'}}}var V=class{constructor(t){this.input=t,this.typeahead=t.closest("actor-typeahead"),this.dropdown=null,this.currentFocus=-1,this.typeaheadClosed=!1,this.init()}init(){this.createDropdown(),this.input.addEventListener("focus",()=>this.handleFocus()),this.input.addEventListener("input",()=>this.handleInput()),this.input.addEventListener("keydown",t=>this.handleKeydown(t)),document.addEventListener("click",t=>{!this.input.contains(t.target)&&!this.dropdown.contains(t.target)&&this.hideDropdown()})}createDropdown(){this.dropdown=document.createElement("div"),this.dropdown.className="recent-accounts-dropdown",this.dropdown.style.display="none",this.typeahead?this.typeahead.insertAdjacentElement("afterend",this.dropdown):this.input.insertAdjacentElement("afterend",this.dropdown)}handleFocus(){this.input.value.trim().length<1&&this.showRecentAccounts()}handleInput(){this.input.value.trim().length>=1&&this.hideDropdown(),this.typeaheadClosed=!1}showRecentAccounts(){let t=this.getRecentAccounts();if(t.length===0){this.hideDropdown();return}this.dropdown.innerHTML="",this.currentFocus=-1;let n=document.createElement("div");n.className="recent-accounts-header",n.textContent="Recent accounts",this.dropdown.appendChild(n),t.forEach((r,o)=>{let i=document.createElement("div");i.className="recent-accounts-item",i.dataset.index=o,i.dataset.handle=r,i.textContent=r,i.addEventListener("click",()=>this.selectItem(r)),this.dropdown.appendChild(i)}),this.dropdown.style.display="block"}selectItem(t){this.input.value=t,this.hideDropdown(),this.input.focus()}hideDropdown(){this.dropdown.style.display="none",this.currentFocus=-1}handleKeydown(t){if(t.key==="Enter"&&this.input.value.trim().length>=2&&(this.typeaheadClosed=!0),t.key==="Tab"&&this.input.value.trim().length>=2&&!this.typeaheadClosed){t.preventDefault();let o=t.shiftKey?"ArrowUp":"ArrowDown",i=new KeyboardEvent("keydown",{key:o,bubbles:!0,cancelable:!0});this.typeahead.dispatchEvent(i);return}if(this.dropdown.style.display==="none")return;let n=this.dropdown.querySelectorAll(".recent-accounts-item");t.key==="ArrowDown"?(t.preventDefault(),this.currentFocus++,this.currentFocus>=n.length&&(this.currentFocus=0),this.updateFocus(n)):t.key==="ArrowUp"?(t.preventDefault(),this.currentFocus--,this.currentFocus<0&&(this.currentFocus=n.length-1),this.updateFocus(n)):t.key==="Enter"&&this.currentFocus>-1&&n[this.currentFocus]?(t.preventDefault(),this.selectItem(n[this.currentFocus].dataset.handle)):t.key==="Escape"&&this.hideDropdown()}updateFocus(t){t.forEach((n,r)=>{n.classList.toggle("focused",r===this.currentFocus)})}getRecentAccounts(){try{let t=localStorage.getItem("atcr_recent_handles");return t?JSON.parse(t):[]}catch{return[]}}saveRecentAccount(t){if(t)try{let n=this.getRecentAccounts();n=n.filter(r=>r!==t),n.unshift(t),n=n.slice(0,5),localStorage.setItem("atcr_recent_handles",JSON.stringify(n))}catch(n){console.error("Failed to save recent account:",n)}}};document.addEventListener("DOMContentLoaded",()=>{let e=document.getElementById("login-form"),t=document.getElementById("handle");e&&t&&new V(t)});document.addEventListener("DOMContentLoaded",()=>{let e=document.cookie.split("; ").find(n=>n.startsWith("atcr_login_handle="));if(!e)return;let t=decodeURIComponent(e.split("=")[1]);if(t){try{let n="atcr_recent_handles",r=JSON.parse(localStorage.getItem(n)||"[]");r=r.filter(o=>o!==t),r.unshift(t),r=r.slice(0,5),localStorage.setItem(n,JSON.stringify(r))}catch(n){console.error("Failed to save recent account:",n)}document.cookie="atcr_login_handle=; path=/; max-age=0"}});function Q(){let e=document.getElementById("featured-carousel"),t=document.getElementById("carousel-prev"),n=document.getElementById("carousel-next");if(!e)return;let r=Array.from(e.querySelectorAll(".carousel-item"));if(r.length===0)return;let o=null,i=5e3,s=0,a=0,l=0;function c(){let b=r[0];if(!b)return;let E=getComputedStyle(e),g=parseFloat(E.gap)||24;s=b.offsetWidth+g,a=e.offsetWidth,l=e.scrollWidth}requestAnimationFrame(()=>{requestAnimationFrame(()=>{c(),m()})});let h;window.addEventListener("resize",()=>{clearTimeout(h),h=setTimeout(c,150)});function u(){return s||c(),s}function f(){return(!a||!s)&&c(),Math.round(a/s)||1}function v(){return(!l||!a)&&c(),l-a}function d(){let b=u(),E=v(),g=e.scrollLeft;g>=E-10?e.scrollTo({left:0,behavior:"smooth"}):e.scrollTo({left:g+b,behavior:"smooth"})}function y(){let b=u(),E=v(),g=e.scrollLeft;g<=10?e.scrollTo({left:E,behavior:"smooth"}):e.scrollTo({left:g-b,behavior:"smooth"})}t&&t.addEventListener("click",()=>{x(),y(),m()}),n&&n.addEventListener("click",()=>{x(),d(),m()});function m(){o||r.length<=f()||(o=setInterval(d,i))}function x(){o&&(clearInterval(o),o=null)}e.addEventListener("mouseenter",x),e.addEventListener("mouseleave",m)}document.addEventListener("DOMContentLoaded",()=>{"requestIdleCallback"in window?requestIdleCallback(Q,{timeout:2e3}):setTimeout(Q,100)});window.setTheme=ee;window.toggleSearch=ue;window.closeSearch=B;window.copyToClipboard=te;window.toggleOfflineManifests=de;window.deleteManifest=he;window.closeManifestDeleteModal=j;window.openVulnDetails=pe;window.htmx=F;
+10
-1
pkg/appview/src/js/app.js
···
85
85
86
86
if (!wrapper || !input) return;
87
87
88
88
-
// Close on Escape key
88
88
+
// Close on Escape key, open on "/" key (GitHub-style)
89
89
document.addEventListener('keydown', (e) => {
90
90
if (e.key === 'Escape' && wrapper.classList.contains('expanded')) {
91
91
closeSearch();
92
92
+
}
93
93
+
94
94
+
if (e.key === '/' && !wrapper.classList.contains('expanded')) {
95
95
+
const tag = e.target.tagName;
96
96
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || e.target.isContentEditable) return;
97
97
+
98
98
+
e.preventDefault();
99
99
+
wrapper.classList.add('expanded');
100
100
+
input.focus();
92
101
}
93
102
});
94
103
+2
-1
pkg/hold/admin/admin.go
···
411
411
r.Post("/admin/relays/crawl", ui.handleRelayCrawl)
412
412
r.Post("/admin/relays/crawl-all", ui.handleRelayCrawlAll)
413
413
414
414
-
// GC POSTs
414
414
+
// GC (background operations + polling status)
415
415
r.Post("/admin/api/gc/preview", ui.handleGCPreview)
416
416
r.Post("/admin/api/gc/run", ui.handleGCRun)
417
417
r.Post("/admin/api/gc/reconcile", ui.handleGCReconcile)
418
418
r.Post("/admin/api/gc/delete-records", ui.handleGCDeleteRecords)
419
419
r.Post("/admin/api/gc/delete-blobs", ui.handleGCDeleteBlobs)
420
420
+
r.Get("/admin/api/gc/status", ui.handleGCStatus)
420
421
421
422
// API endpoints (for HTMX)
422
423
r.Get("/admin/api/stats", ui.handleStatsAPI)
+120
-78
pkg/hold/admin/handlers_gc.go
···
21
21
LastResultAge string
22
22
}
23
23
24
24
+
// gcProgressData is the data passed to the gc_progress.html partial
25
25
+
type gcProgressData struct {
26
26
+
Phase string
27
27
+
Message string
28
28
+
OpType string
29
29
+
}
30
30
+
24
31
// handleGCTab returns the storage/GC tab content (HTMX partial)
25
32
func (ui *AdminUI) handleGCTab(w http.ResponseWriter, r *http.Request) {
26
33
if ui.gc == nil {
···
44
51
ui.renderTemplate(w, "partials/tab_storage.html", data)
45
52
}
46
53
47
47
-
// handleGCPreview runs a GC preview (analysis only, no mutations)
54
54
+
// handleGCPreview starts a GC preview in the background
48
55
func (ui *AdminUI) handleGCPreview(w http.ResponseWriter, r *http.Request) {
49
56
if ui.gc == nil {
50
57
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"GC not available"})
51
58
return
52
59
}
53
60
54
54
-
preview, err := ui.gc.Preview(r.Context())
55
55
-
if err != nil {
56
56
-
slog.Error("GC preview failed", "error", err)
57
57
-
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{err.Error()})
58
58
-
return
59
59
-
}
60
60
-
61
61
session := getSessionFromContext(r.Context())
62
62
-
slog.Info("GC preview completed via admin panel",
63
63
-
"orphanedRecords", len(preview.OrphanedRecords),
64
64
-
"orphanedBlobs", len(preview.OrphanedBlobs),
65
65
-
"missingRecords", len(preview.MissingRecords),
66
66
-
"duration", preview.Duration,
67
67
-
"by", session.DID)
68
62
69
69
-
ui.renderTemplate(w, "partials/gc_preview.html", struct {
70
70
-
Preview *gc.GCPreview
71
71
-
}{Preview: preview})
63
63
+
if ui.gc.StartPreview() {
64
64
+
slog.Info("GC preview started via admin panel", "by", session.DID)
65
65
+
}
66
66
+
67
67
+
// Whether we just started or it was already running, show progress
68
68
+
progress := ui.gc.GetProgress()
69
69
+
ui.renderTemplate(w, "partials/gc_progress.html", gcProgressData{
70
70
+
Phase: progress.Phase,
71
71
+
Message: progress.Message,
72
72
+
OpType: progress.OperationType,
73
73
+
})
72
74
}
73
75
74
74
-
// handleGCRun executes an actual GC run
76
76
+
// handleGCRun starts a full GC run in the background
75
77
func (ui *AdminUI) handleGCRun(w http.ResponseWriter, r *http.Request) {
76
78
if ui.gc == nil {
77
79
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"GC not available"})
78
80
return
79
81
}
80
82
81
81
-
result, err := ui.gc.Run(r.Context())
82
82
-
if err != nil {
83
83
-
slog.Error("GC run failed", "error", err)
84
84
-
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{err.Error()})
85
85
-
return
83
83
+
session := getSessionFromContext(r.Context())
84
84
+
85
85
+
if ui.gc.StartRun() {
86
86
+
slog.Info("GC run started via admin panel", "by", session.DID)
86
87
}
87
88
88
88
-
session := getSessionFromContext(r.Context())
89
89
-
slog.Info("GC run completed via admin panel",
90
90
-
"blobsDeleted", result.BlobsDeleted,
91
91
-
"bytesReclaimed", result.BytesReclaimed,
92
92
-
"recordsDeleted", result.RecordsDeleted,
93
93
-
"recordsReconciled", result.RecordsReconciled,
94
94
-
"duration", result.Duration,
95
95
-
"by", session.DID)
96
96
-
97
97
-
ui.renderTemplate(w, "partials/gc_result.html", struct {
98
98
-
Result *gc.GCResult
99
99
-
}{Result: result})
89
89
+
progress := ui.gc.GetProgress()
90
90
+
ui.renderTemplate(w, "partials/gc_progress.html", gcProgressData{
91
91
+
Phase: progress.Phase,
92
92
+
Message: progress.Message,
93
93
+
OpType: progress.OperationType,
94
94
+
})
100
95
}
101
96
102
102
-
// handleGCReconcile creates missing layer records without deleting anything
97
97
+
// handleGCReconcile starts record reconciliation in the background
103
98
func (ui *AdminUI) handleGCReconcile(w http.ResponseWriter, r *http.Request) {
104
99
if ui.gc == nil {
105
100
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"GC not available"})
106
101
return
107
102
}
108
103
109
109
-
result, err := ui.gc.Reconcile(r.Context())
110
110
-
if err != nil {
111
111
-
slog.Error("GC reconcile failed", "error", err)
112
112
-
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{err.Error()})
113
113
-
return
104
104
+
session := getSessionFromContext(r.Context())
105
105
+
106
106
+
if ui.gc.StartReconcile() {
107
107
+
slog.Info("GC reconcile started via admin panel", "by", session.DID)
114
108
}
115
109
116
116
-
session := getSessionFromContext(r.Context())
117
117
-
slog.Info("GC reconcile completed via admin panel",
118
118
-
"recordsReconciled", result.RecordsReconciled,
119
119
-
"duration", result.Duration,
120
120
-
"by", session.DID)
121
121
-
122
122
-
ui.renderTemplate(w, "partials/gc_result.html", struct {
123
123
-
Result *gc.GCResult
124
124
-
}{Result: result})
110
110
+
progress := ui.gc.GetProgress()
111
111
+
ui.renderTemplate(w, "partials/gc_progress.html", gcProgressData{
112
112
+
Phase: progress.Phase,
113
113
+
Message: progress.Message,
114
114
+
OpType: progress.OperationType,
115
115
+
})
125
116
}
126
117
127
127
-
// handleGCDeleteRecords deletes orphaned layer records (no blob deletion)
118
118
+
// handleGCDeleteRecords starts orphaned record deletion in the background
128
119
func (ui *AdminUI) handleGCDeleteRecords(w http.ResponseWriter, r *http.Request) {
129
120
if ui.gc == nil {
130
121
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"GC not available"})
131
122
return
132
123
}
133
124
134
134
-
result, err := ui.gc.DeleteOrphanedRecords(r.Context())
135
135
-
if err != nil {
136
136
-
slog.Error("GC delete records failed", "error", err)
137
137
-
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{err.Error()})
125
125
+
session := getSessionFromContext(r.Context())
126
126
+
127
127
+
if ui.gc.StartDeleteRecords() {
128
128
+
slog.Info("GC delete records started via admin panel", "by", session.DID)
129
129
+
}
130
130
+
131
131
+
progress := ui.gc.GetProgress()
132
132
+
ui.renderTemplate(w, "partials/gc_progress.html", gcProgressData{
133
133
+
Phase: progress.Phase,
134
134
+
Message: progress.Message,
135
135
+
OpType: progress.OperationType,
136
136
+
})
137
137
+
}
138
138
+
139
139
+
// handleGCDeleteBlobs starts orphaned blob deletion in the background
140
140
+
func (ui *AdminUI) handleGCDeleteBlobs(w http.ResponseWriter, r *http.Request) {
141
141
+
if ui.gc == nil {
142
142
+
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"GC not available"})
138
143
return
139
144
}
140
145
141
146
session := getSessionFromContext(r.Context())
142
142
-
slog.Info("GC delete orphaned records completed via admin panel",
143
143
-
"recordsDeleted", result.RecordsDeleted,
144
144
-
"orphanedRecords", result.OrphanedRecords,
145
145
-
"duration", result.Duration,
146
146
-
"by", session.DID)
147
147
148
148
-
ui.renderTemplate(w, "partials/gc_result.html", struct {
149
149
-
Result *gc.GCResult
150
150
-
}{Result: result})
148
148
+
if ui.gc.StartDeleteBlobs() {
149
149
+
slog.Info("GC delete blobs started via admin panel", "by", session.DID)
150
150
+
}
151
151
+
152
152
+
progress := ui.gc.GetProgress()
153
153
+
ui.renderTemplate(w, "partials/gc_progress.html", gcProgressData{
154
154
+
Phase: progress.Phase,
155
155
+
Message: progress.Message,
156
156
+
OpType: progress.OperationType,
157
157
+
})
151
158
}
152
159
153
153
-
// handleGCDeleteBlobs walks S3 and deletes unreferenced blobs
154
154
-
func (ui *AdminUI) handleGCDeleteBlobs(w http.ResponseWriter, r *http.Request) {
160
160
+
// handleGCStatus returns current progress or final results (polled by gc_progress.html)
161
161
+
func (ui *AdminUI) handleGCStatus(w http.ResponseWriter, r *http.Request) {
155
162
if ui.gc == nil {
156
163
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"GC not available"})
157
164
return
158
165
}
159
166
160
160
-
result, err := ui.gc.DeleteOrphanedBlobs(r.Context())
161
161
-
if err != nil {
162
162
-
slog.Error("GC delete blobs failed", "error", err)
163
163
-
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{err.Error()})
167
167
+
progress := ui.gc.GetProgress()
168
168
+
169
169
+
// Still running — return progress partial (which will poll again)
170
170
+
if progress.Running {
171
171
+
ui.renderTemplate(w, "partials/gc_progress.html", gcProgressData{
172
172
+
Phase: progress.Phase,
173
173
+
Message: progress.Message,
174
174
+
OpType: progress.OperationType,
175
175
+
})
176
176
+
return
177
177
+
}
178
178
+
179
179
+
// Error — show error
180
180
+
if progress.Phase == "error" {
181
181
+
slog.Error("GC operation failed", "type", progress.OperationType, "error", progress.Error)
182
182
+
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{progress.Error})
164
183
return
165
184
}
166
185
167
167
-
session := getSessionFromContext(r.Context())
168
168
-
slog.Info("GC delete orphaned blobs completed via admin panel",
169
169
-
"blobsDeleted", result.BlobsDeleted,
170
170
-
"bytesReclaimed", result.BytesReclaimed,
171
171
-
"duration", result.Duration,
172
172
-
"by", session.DID)
186
186
+
// Complete — render final results based on operation type
187
187
+
switch progress.OperationType {
188
188
+
case "preview":
189
189
+
preview, _ := ui.gc.LastPreview()
190
190
+
if preview == nil {
191
191
+
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"No preview results available"})
192
192
+
return
193
193
+
}
194
194
+
slog.Info("GC preview completed via admin panel",
195
195
+
"orphanedRecords", len(preview.OrphanedRecords),
196
196
+
"orphanedBlobs", len(preview.OrphanedBlobs),
197
197
+
"missingRecords", len(preview.MissingRecords),
198
198
+
"duration", preview.Duration)
199
199
+
ui.renderTemplate(w, "partials/gc_preview.html", struct {
200
200
+
Preview *gc.GCPreview
201
201
+
}{Preview: preview})
173
202
174
174
-
ui.renderTemplate(w, "partials/gc_result.html", struct {
175
175
-
Result *gc.GCResult
176
176
-
}{Result: result})
203
203
+
default:
204
204
+
result, _ := ui.gc.LastResult()
205
205
+
if result == nil {
206
206
+
ui.renderTemplate(w, "partials/gc_error.html", struct{ Error string }{"No results available"})
207
207
+
return
208
208
+
}
209
209
+
slog.Info("GC operation completed via admin panel",
210
210
+
"type", progress.OperationType,
211
211
+
"blobsDeleted", result.BlobsDeleted,
212
212
+
"recordsDeleted", result.RecordsDeleted,
213
213
+
"recordsReconciled", result.RecordsReconciled,
214
214
+
"duration", result.Duration)
215
215
+
ui.renderTemplate(w, "partials/gc_result.html", struct {
216
216
+
Result *gc.GCResult
217
217
+
}{Result: result})
218
218
+
}
177
219
}
178
220
179
221
// timeAgo returns a human-readable relative time string
+3
-6
pkg/hold/admin/templates/partials/gc_preview.html
···
142
142
<button class="btn btn-warning gap-2"
143
143
hx-post="/admin/api/gc/reconcile"
144
144
hx-target="#gc-results"
145
145
-
hx-swap="innerHTML"
146
146
-
hx-indicator="#gc-loading">
145
145
+
hx-swap="innerHTML">
147
146
{{ icon "file-plus" "size-4" }}
148
147
Reconcile {{len .Preview.MissingRecords}} Records
149
148
</button>
···
153
152
hx-post="/admin/api/gc/delete-records"
154
153
hx-target="#gc-results"
155
154
hx-swap="innerHTML"
156
156
-
hx-confirm="Delete {{len .Preview.OrphanedRecords}} orphaned layer records?"
157
157
-
hx-indicator="#gc-loading">
155
155
+
hx-confirm="Delete {{len .Preview.OrphanedRecords}} orphaned layer records?">
158
156
{{ icon "file-x" "size-4" }}
159
157
Delete {{len .Preview.OrphanedRecords}} Orphaned Records
160
158
</button>
···
164
162
hx-post="/admin/api/gc/delete-blobs"
165
163
hx-target="#gc-results"
166
164
hx-swap="innerHTML"
167
167
-
hx-confirm="Delete {{len .Preview.OrphanedBlobs}} orphaned blobs from S3? This cannot be undone."
168
168
-
hx-indicator="#gc-loading">
165
165
+
hx-confirm="Delete {{len .Preview.OrphanedBlobs}} orphaned blobs from S3? This cannot be undone.">
169
166
{{ icon "trash-2" "size-4" }}
170
167
Delete {{len .Preview.OrphanedBlobs}} Orphaned Blobs
171
168
</button>
+21
pkg/hold/admin/templates/partials/gc_progress.html
···
1
1
+
{{define "partials/gc_progress.html"}}
2
2
+
<div hx-get="/admin/api/gc/status"
3
3
+
hx-trigger="load delay:2s"
4
4
+
hx-target="#gc-results"
5
5
+
hx-swap="innerHTML">
6
6
+
<div class="flex items-center gap-3 p-4 bg-base-100 rounded-lg shadow-sm">
7
7
+
<span class="loading loading-spinner loading-md text-primary"></span>
8
8
+
<div>
9
9
+
<p class="font-medium">{{.Message}}</p>
10
10
+
<p class="text-sm text-base-content/50">
11
11
+
{{if eq .Phase "manifests"}}Fetching manifests from user PDS instances...
12
12
+
{{else if eq .Phase "records"}}Scanning layer records...
13
13
+
{{else if eq .Phase "blobs"}}Walking S3 storage...
14
14
+
{{else if eq .Phase "deleting"}}Processing changes...
15
15
+
{{else}}Working...
16
16
+
{{end}}
17
17
+
</p>
18
18
+
</div>
19
19
+
</div>
20
20
+
</div>
21
21
+
{{end}}
+2
-2
pkg/hold/admin/templates/partials/relay_status.html
···
33
33
{{if .RepoStatus}}
34
34
{{if .RepoStatus.Active}}
35
35
{{if eq .RepoStatus.Rev $.CurrentRev}}
36
36
-
<span class="text-sm text-success">Known (rev: {{truncate .RepoStatus.Rev 12}})</span>
36
36
+
<span class="text-sm text-success">Known (rev: {{.RepoStatus.Rev}})</span>
37
37
{{else}}
38
38
-
<span class="text-sm text-warning">Behind (rev: {{truncate .RepoStatus.Rev 12}})</span>
38
38
+
<span class="text-sm text-warning">Behind (rev: {{.RepoStatus.Rev}})</span>
39
39
{{end}}
40
40
{{else}}
41
41
<span class="text-sm text-warning">Inactive</span>
+13
-11
pkg/hold/admin/templates/partials/tab_storage.html
···
37
37
hx-post="/admin/api/gc/preview"
38
38
hx-target="#gc-results"
39
39
hx-swap="innerHTML"
40
40
-
hx-indicator="#gc-loading"
41
40
{{if .Running}}disabled{{end}}>
42
41
{{ icon "search" "size-4" }}
43
42
Scan for Orphans
44
43
</button>
45
44
</div>
46
45
47
47
-
<div id="gc-loading" class="htmx-indicator mb-4">
48
48
-
<div class="flex items-center gap-3 p-4 bg-base-100 rounded-lg shadow-sm">
49
49
-
<span class="loading loading-spinner loading-md text-primary"></span>
50
50
-
<div>
51
51
-
<p class="font-medium">Scanning storage...</p>
52
52
-
<p class="text-sm text-base-content/50">This may take a few minutes for large holds.</p>
46
46
+
<div id="gc-results">
47
47
+
{{if .Running}}
48
48
+
<div hx-get="/admin/api/gc/status"
49
49
+
hx-trigger="load delay:2s"
50
50
+
hx-target="#gc-results"
51
51
+
hx-swap="innerHTML">
52
52
+
<div class="flex items-center gap-3 p-4 bg-base-100 rounded-lg shadow-sm">
53
53
+
<span class="loading loading-spinner loading-md text-primary"></span>
54
54
+
<div>
55
55
+
<p class="font-medium">Operation in progress...</p>
56
56
+
<p class="text-sm text-base-content/50">Checking status...</p>
57
57
+
</div>
53
58
</div>
54
59
</div>
55
55
-
</div>
56
56
-
57
57
-
<div id="gc-results">
58
58
-
<!-- Preview or run results will be swapped in here -->
60
60
+
{{end}}
59
61
</div>
60
62
{{end}}
+258
-15
pkg/hold/gc/gc.go
···
5
5
"context"
6
6
"encoding/json"
7
7
"fmt"
8
8
+
"io"
8
9
"log/slog"
9
10
"net/http"
11
11
+
"net/url"
10
12
"regexp"
11
13
"strings"
12
14
"sync"
···
82
84
lastPreviewAt time.Time
83
85
lastResult *GCResult
84
86
lastResultAt time.Time
87
87
+
88
88
+
// Progress tracking for background operations
89
89
+
phase string // "manifests", "records", "blobs", "deleting", "complete", "error"
90
90
+
progressMsg string // e.g. "Fetching manifests (35/69 users)"
91
91
+
operationType string // "preview", "run", "reconcile", "delete-records", "delete-blobs"
92
92
+
lastError error
93
93
+
94
94
+
// predecessorCache caches holdDID → "is this a predecessor of our hold?"
95
95
+
// A predecessor is a hold whose captain record has a successor label set.
96
96
+
predecessorCache map[string]bool
85
97
}
86
98
87
99
// GCResult contains statistics from a GC run
···
119
131
// NewGarbageCollector creates a new GC instance
120
132
func NewGarbageCollector(holdPDS *pds.HoldPDS, s3svc *s3.S3Service, cfg Config) *GarbageCollector {
121
133
return &GarbageCollector{
122
122
-
pds: holdPDS,
123
123
-
s3: s3svc,
124
124
-
cfg: cfg,
125
125
-
logger: slog.Default().With("component", "gc"),
126
126
-
stopCh: make(chan struct{}),
134
134
+
pds: holdPDS,
135
135
+
s3: s3svc,
136
136
+
cfg: cfg,
137
137
+
logger: slog.Default().With("component", "gc"),
138
138
+
stopCh: make(chan struct{}),
139
139
+
predecessorCache: make(map[string]bool),
127
140
}
128
141
}
129
142
···
145
158
gc.mu.Unlock()
146
159
}
147
160
161
161
+
// setProgress updates the progress fields (thread-safe).
162
162
+
func (gc *GarbageCollector) setProgress(phase, msg, opType string) {
163
163
+
gc.mu.Lock()
164
164
+
gc.phase = phase
165
165
+
gc.progressMsg = msg
166
166
+
gc.operationType = opType
167
167
+
if phase != "error" {
168
168
+
gc.lastError = nil
169
169
+
}
170
170
+
gc.mu.Unlock()
171
171
+
}
172
172
+
173
173
+
// GCProgress holds a snapshot of the current GC operation progress.
174
174
+
type GCProgress struct {
175
175
+
Phase string // "manifests", "records", "blobs", "deleting", "complete", "error"
176
176
+
Message string
177
177
+
OperationType string // "preview", "run", "reconcile", "delete-records", "delete-blobs"
178
178
+
Running bool
179
179
+
Error string
180
180
+
}
181
181
+
182
182
+
// GetProgress returns the current progress state.
183
183
+
func (gc *GarbageCollector) GetProgress() GCProgress {
184
184
+
gc.mu.Lock()
185
185
+
defer gc.mu.Unlock()
186
186
+
p := GCProgress{
187
187
+
Phase: gc.phase,
188
188
+
Message: gc.progressMsg,
189
189
+
OperationType: gc.operationType,
190
190
+
Running: gc.running,
191
191
+
}
192
192
+
if gc.lastError != nil {
193
193
+
p.Error = gc.lastError.Error()
194
194
+
}
195
195
+
return p
196
196
+
}
197
197
+
198
198
+
// startBackground is the common pattern for launching a GC operation in the background.
199
199
+
// Returns false if already running.
200
200
+
func (gc *GarbageCollector) startBackground(opType, initialPhase, initialMsg string, fn func(ctx context.Context) error) bool {
201
201
+
if !gc.tryStart() {
202
202
+
return false
203
203
+
}
204
204
+
gc.setProgress(initialPhase, initialMsg, opType)
205
205
+
go func() {
206
206
+
defer gc.finish()
207
207
+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
208
208
+
defer cancel()
209
209
+
210
210
+
if err := fn(ctx); err != nil {
211
211
+
gc.mu.Lock()
212
212
+
gc.phase = "error"
213
213
+
gc.progressMsg = err.Error()
214
214
+
gc.lastError = err
215
215
+
gc.mu.Unlock()
216
216
+
gc.logger.Error("GC operation failed", "type", opType, "error", err)
217
217
+
return
218
218
+
}
219
219
+
gc.setProgress("complete", "", opType)
220
220
+
}()
221
221
+
return true
222
222
+
}
223
223
+
224
224
+
// StartPreview launches a GC preview in the background.
225
225
+
func (gc *GarbageCollector) StartPreview() bool {
226
226
+
return gc.startBackground("preview", "manifests", "Starting preview...", func(ctx context.Context) error {
227
227
+
_, err := gc.doPreview(ctx)
228
228
+
return err
229
229
+
})
230
230
+
}
231
231
+
232
232
+
// StartRun launches a full GC run in the background.
233
233
+
func (gc *GarbageCollector) StartRun() bool {
234
234
+
return gc.startBackground("run", "manifests", "Starting GC run...", func(ctx context.Context) error {
235
235
+
_, err := gc.doRun(ctx)
236
236
+
return err
237
237
+
})
238
238
+
}
239
239
+
240
240
+
// StartReconcile launches record reconciliation in the background.
241
241
+
func (gc *GarbageCollector) StartReconcile() bool {
242
242
+
return gc.startBackground("reconcile", "deleting", "Reconciling missing records...", func(ctx context.Context) error {
243
243
+
_, err := gc.doReconcile(ctx)
244
244
+
return err
245
245
+
})
246
246
+
}
247
247
+
248
248
+
// StartDeleteRecords launches orphaned record deletion in the background.
249
249
+
func (gc *GarbageCollector) StartDeleteRecords() bool {
250
250
+
return gc.startBackground("delete-records", "deleting", "Deleting orphaned records...", func(ctx context.Context) error {
251
251
+
_, err := gc.doDeleteOrphanedRecords(ctx)
252
252
+
return err
253
253
+
})
254
254
+
}
255
255
+
256
256
+
// StartDeleteBlobs launches orphaned blob deletion in the background.
257
257
+
func (gc *GarbageCollector) StartDeleteBlobs() bool {
258
258
+
return gc.startBackground("delete-blobs", "manifests", "Analyzing records before blob deletion...", func(ctx context.Context) error {
259
259
+
_, err := gc.doDeleteOrphanedBlobs(ctx)
260
260
+
return err
261
261
+
})
262
262
+
}
263
263
+
148
264
// Start begins the GC background process with a nightly ticker
149
265
func (gc *GarbageCollector) Start(ctx context.Context) {
150
266
if !gc.cfg.Enabled {
···
194
310
return nil, fmt.Errorf("GC operation already in progress")
195
311
}
196
312
defer gc.finish()
313
313
+
return gc.doRun(ctx)
314
314
+
}
197
315
316
316
+
// doRun is the internal implementation of Run (caller must hold the running lock).
317
317
+
func (gc *GarbageCollector) doRun(ctx context.Context) (*GCResult, error) {
198
318
start := time.Now()
199
319
result := &GCResult{}
200
320
···
216
336
"missingRecords", len(analysis.missingDetails))
217
337
218
338
// Reconcile: create missing layer records
339
339
+
gc.setProgress("deleting", "Reconciling missing records...", "run")
219
340
if len(analysis.missingDetails) > 0 {
220
341
gc.reconcileMissingRecords(ctx, analysis.missingDetails, result)
221
342
}
222
343
223
344
// Phase 2: Delete orphaned layer records
345
345
+
gc.setProgress("deleting", "Deleting orphaned records...", "run")
224
346
if err := gc.deleteOrphanedRecords(ctx, analysis.orphanedRkeys, result); err != nil {
225
347
gc.logger.Error("Phase 2 (delete orphaned records) failed", "error", err)
226
348
// Continue to phase 3 - we can still clean up blobs
227
349
}
228
350
229
351
// Phase 3: Walk storage and delete unreferenced blobs
352
352
+
gc.setProgress("blobs", "Deleting orphaned blobs...", "run")
230
353
if err := gc.deleteOrphanedBlobs(ctx, analysis.referenced, result); err != nil {
231
354
return nil, fmt.Errorf("phase 3 (delete orphaned blobs) failed: %w", err)
232
355
}
···
250
373
return nil, fmt.Errorf("GC operation already in progress")
251
374
}
252
375
defer gc.finish()
376
376
+
return gc.doPreview(ctx)
377
377
+
}
253
378
379
379
+
// doPreview is the internal implementation of Preview (caller must hold the running lock).
380
380
+
func (gc *GarbageCollector) doPreview(ctx context.Context) (*GCPreview, error) {
254
381
start := time.Now()
255
382
256
383
gc.logger.Info("Starting GC preview")
···
262
389
}
263
390
264
391
// Phase 2: Walk S3 to find orphaned blobs (read-only)
392
392
+
gc.setProgress("blobs", "Walking S3 storage...", "preview")
265
393
orphanedBlobs, totalBlobs, err := gc.scanOrphanedBlobDetails(ctx, analysis.referenced)
266
394
if err != nil {
267
395
return nil, fmt.Errorf("scan orphaned blobs: %w", err)
···
303
431
return nil, fmt.Errorf("GC operation already in progress")
304
432
}
305
433
defer gc.finish()
434
434
+
return gc.doReconcile(ctx)
435
435
+
}
306
436
437
437
+
// doReconcile is the internal implementation of Reconcile (caller must hold the running lock).
438
438
+
func (gc *GarbageCollector) doReconcile(ctx context.Context) (*GCResult, error) {
307
439
gc.mu.Lock()
308
440
preview := gc.lastPreview
309
441
gc.mu.Unlock()
···
337
469
return nil, fmt.Errorf("GC operation already in progress")
338
470
}
339
471
defer gc.finish()
472
472
+
return gc.doDeleteOrphanedRecords(ctx)
473
473
+
}
340
474
475
475
+
// doDeleteOrphanedRecords is the internal implementation (caller must hold the running lock).
476
476
+
func (gc *GarbageCollector) doDeleteOrphanedRecords(ctx context.Context) (*GCResult, error) {
341
477
gc.mu.Lock()
342
478
preview := gc.lastPreview
343
479
gc.mu.Unlock()
···
381
517
return nil, fmt.Errorf("GC operation already in progress")
382
518
}
383
519
defer gc.finish()
520
520
+
return gc.doDeleteOrphanedBlobs(ctx)
521
521
+
}
384
522
523
523
+
// doDeleteOrphanedBlobs is the internal implementation (caller must hold the running lock).
524
524
+
func (gc *GarbageCollector) doDeleteOrphanedBlobs(ctx context.Context) (*GCResult, error) {
385
525
start := time.Now()
386
526
result := &GCResult{}
387
527
···
395
535
396
536
result.ReferencedBlobs = int64(len(analysis.referenced))
397
537
538
538
+
gc.setProgress("blobs", "Deleting orphaned blobs...", "delete-blobs")
398
539
if err := gc.deleteOrphanedBlobs(ctx, analysis.referenced, result); err != nil {
399
540
return nil, fmt.Errorf("delete orphaned blobs: %w", err)
400
541
}
···
432
573
knownManifests := make(map[string]*manifestInfo)
433
574
fetchedUsers := make(map[string]bool)
434
575
576
576
+
totalUsers := len(userDIDs)
435
577
for _, did := range userDIDs {
436
578
result.usersChecked++
579
579
+
gc.setProgress("manifests", fmt.Sprintf("Fetching manifests (%d/%d users)", result.usersChecked, totalUsers), gc.operationType)
437
580
438
581
manifests, err := gc.fetchUserManifests(ctx, did)
439
582
if err != nil {
···
464
607
"fetchedUsers", len(fetchedUsers))
465
608
466
609
// Step 3: Scan existing layer records to find orphans and build coveredPairs
610
610
+
gc.setProgress("records", "Scanning layer records...", gc.operationType)
467
611
coveredPairs := make(map[string]bool)
468
612
469
613
cursor := ""
···
599
743
600
744
// reconcileMissingRecords creates layer records for manifest+layer pairs that are missing.
601
745
func (gc *GarbageCollector) reconcileMissingRecords(ctx context.Context, missing []MissingRecordDetail, result *GCResult) {
602
602
-
for _, m := range missing {
746
746
+
for i, m := range missing {
603
747
record := atproto.NewLayerRecord(
604
748
m.Digest,
605
749
m.Size,
···
615
759
continue
616
760
}
617
761
result.RecordsReconciled++
618
618
-
gc.logger.Info("Created missing layer record",
619
619
-
"digest", m.Digest,
620
620
-
"manifest", m.ManifestURI,
621
621
-
"user", m.UserDID)
762
762
+
if result.RecordsReconciled%100 == 0 {
763
763
+
gc.logger.Info("Reconciliation progress",
764
764
+
"created", result.RecordsReconciled,
765
765
+
"total", len(missing))
766
766
+
}
767
767
+
768
768
+
// Throttle to avoid flooding the firehose (~100 records/sec)
769
769
+
if i < len(missing)-1 {
770
770
+
time.Sleep(10 * time.Millisecond)
771
771
+
}
622
772
}
623
773
624
774
if result.RecordsReconciled > 0 {
···
751
901
return manifests, nil
752
902
}
753
903
754
754
-
// manifestBelongsToHold checks if a manifest references this hold via HoldDID or legacy HoldEndpoint.
904
904
+
// manifestBelongsToHold checks if a manifest references this hold via HoldDID,
905
905
+
// legacy HoldEndpoint, or a predecessor hold that has been migrated.
755
906
func (gc *GarbageCollector) manifestBelongsToHold(ctx context.Context, manifest *atproto.ManifestRecord, holdDID string) bool {
756
756
-
if manifest.HoldDID == holdDID {
907
907
+
manifestHoldDID := manifest.HoldDID
908
908
+
909
909
+
// Direct match
910
910
+
if manifestHoldDID == holdDID {
757
911
return true
758
912
}
759
759
-
// Legacy: check holdEndpoint converted to DID
760
760
-
if manifest.HoldEndpoint != "" {
913
913
+
914
914
+
// Legacy: resolve holdEndpoint to DID
915
915
+
if manifestHoldDID == "" && manifest.HoldEndpoint != "" {
761
916
resolved, err := atproto.ResolveHoldDID(ctx, manifest.HoldEndpoint)
762
917
if err != nil {
763
918
gc.logger.Debug("Failed to resolve hold DID from legacy endpoint", "holdEndpoint", manifest.HoldEndpoint, "error", err)
764
919
return false
765
920
}
766
766
-
return resolved == holdDID
921
921
+
manifestHoldDID = resolved
922
922
+
if manifestHoldDID == holdDID {
923
923
+
return true
924
924
+
}
767
925
}
926
926
+
927
927
+
if manifestHoldDID == "" {
928
928
+
return false
929
929
+
}
930
930
+
931
931
+
// Check if the manifest's hold is a predecessor (has a successor label set)
932
932
+
return gc.isPredecessorHold(ctx, manifestHoldDID)
933
933
+
}
934
934
+
935
935
+
// isPredecessorHold checks if the given holdDID is a predecessor of this hold
936
936
+
// by fetching its captain record and checking for a successor label.
937
937
+
// Results are cached to avoid repeated network calls.
938
938
+
func (gc *GarbageCollector) isPredecessorHold(ctx context.Context, holdDID string) bool {
939
939
+
if gc.predecessorCache == nil {
940
940
+
gc.predecessorCache = make(map[string]bool)
941
941
+
}
942
942
+
943
943
+
if isPredecessor, cached := gc.predecessorCache[holdDID]; cached {
944
944
+
return isPredecessor
945
945
+
}
946
946
+
947
947
+
isPredecessor := gc.checkPredecessor(ctx, holdDID)
948
948
+
gc.predecessorCache[holdDID] = isPredecessor
949
949
+
return isPredecessor
950
950
+
}
951
951
+
952
952
+
// checkPredecessor fetches a hold's captain record to check if it has a successor label
953
953
+
// (meaning the hold has been migrated/retired and its blobs are served by this hold).
954
954
+
func (gc *GarbageCollector) checkPredecessor(ctx context.Context, holdDID string) bool {
955
955
+
fetchCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
956
956
+
defer cancel()
957
957
+
958
958
+
holdURL, err := atproto.ResolveHoldURL(fetchCtx, holdDID)
959
959
+
if err != nil {
960
960
+
gc.logger.Debug("GC: failed to resolve predecessor hold URL",
961
961
+
"holdDID", holdDID, "error", err)
962
962
+
return false
963
963
+
}
964
964
+
965
965
+
recordURL := fmt.Sprintf("%s/xrpc/com.atproto.repo.getRecord?repo=%s&collection=%s&rkey=self",
966
966
+
holdURL,
967
967
+
url.QueryEscape(holdDID),
968
968
+
url.QueryEscape(atproto.CaptainCollection),
969
969
+
)
970
970
+
971
971
+
req, err := http.NewRequestWithContext(fetchCtx, "GET", recordURL, nil)
972
972
+
if err != nil {
973
973
+
return false
974
974
+
}
975
975
+
976
976
+
resp, err := http.DefaultClient.Do(req)
977
977
+
if err != nil {
978
978
+
gc.logger.Debug("GC: failed to fetch predecessor captain record",
979
979
+
"holdDID", holdDID, "error", err)
980
980
+
return false
981
981
+
}
982
982
+
defer resp.Body.Close()
983
983
+
984
984
+
if resp.StatusCode != http.StatusOK {
985
985
+
return false
986
986
+
}
987
987
+
988
988
+
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
989
989
+
if err != nil {
990
990
+
return false
991
991
+
}
992
992
+
993
993
+
var envelope struct {
994
994
+
Value json.RawMessage `json:"value"`
995
995
+
}
996
996
+
if err := json.Unmarshal(body, &envelope); err != nil {
997
997
+
return false
998
998
+
}
999
999
+
1000
1000
+
var captain atproto.CaptainRecord
1001
1001
+
if err := json.Unmarshal(envelope.Value, &captain); err != nil {
1002
1002
+
return false
1003
1003
+
}
1004
1004
+
1005
1005
+
if captain.Successor != "" {
1006
1006
+
gc.logger.Info("GC: discovered predecessor hold (has successor label)",
1007
1007
+
"holdDID", holdDID, "successor", captain.Successor)
1008
1008
+
return true
1009
1009
+
}
1010
1010
+
768
1011
return false
769
1012
}
770
1013